diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 71ce65841..cce83ac87 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -347,23 +347,6 @@ limitations under the License. - - - - - - - - - - - - - toPreferenceIdLabelMap(final Resources resources, final TrackFileFormat ... trackFileFormats) { + Map preferenceIdLabelMap = new LinkedHashMap<>(trackFileFormats.length); + for (TrackFileFormat trackFileFormat : trackFileFormats) { + String trackFileFormatUpperCase = trackFileFormat.getExtension().toUpperCase(Locale.US); //ASCII upper case + int photoMessageId = trackFileFormat.includesPhotos() ? R.string.export_with_photos : R.string.export_without_photos; + preferenceIdLabelMap.put(trackFileFormat.getPreferenceId(), String.format("%s (%s)", trackFileFormatUpperCase, resources.getString(photoMessageId))); + } + return preferenceIdLabelMap; + } + + public static TrackFileFormat valueOfPreferenceId(final String preferenceId) { + return Arrays.stream(values()) + .filter(trackFileFormat -> trackFileFormat.getPreferenceId().equals(preferenceId)) + .findFirst() + .orElse(null); + } + /** * Returns the mime type for each format. */ diff --git a/src/main/java/de/dennisguse/opentracks/settings/ImportExportSettingsFragment.java b/src/main/java/de/dennisguse/opentracks/settings/ImportExportSettingsFragment.java index 66eb796b8..ca03446eb 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/ImportExportSettingsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/settings/ImportExportSettingsFragment.java @@ -9,7 +9,7 @@ import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; -import java.util.Locale; +import java.util.Map; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.io.file.TrackFileFormat; @@ -46,27 +46,15 @@ public class ImportExportSettingsFragment extends PreferenceFragmentCompat { } private void setExportTrackFileFormatOptions() { - final TrackFileFormat[] trackFileFormats = { + Map options = TrackFileFormat.toPreferenceIdLabelMap(getResources(), TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES, TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.GPX, - TrackFileFormat.CSV - }; - String[] entries = new String[trackFileFormats.length]; - String[] entryValues = new String[trackFileFormats.length]; - - for (int i = 0; i < entries.length; i++) { - TrackFileFormat trackFileFormat = trackFileFormats[i]; - String trackFileFormatUpperCase = trackFileFormat.getExtension().toUpperCase(Locale.US); //ASCII upper case - int photoMessageId = trackFileFormat.includesPhotos() ? R.string.export_with_photos : R.string.export_without_photos; - entries[i] = String.format("%s (%s)", trackFileFormatUpperCase, getString(photoMessageId)); - entryValues[i] = trackFileFormat.getPreferenceId(); - } - + TrackFileFormat.CSV); ListPreference listPreference = findPreference(getString(R.string.export_trackfileformat_key)); - listPreference.setEntries(entries); - listPreference.setEntryValues(entryValues); + listPreference.setEntries(options.values().toArray(new String[0])); + listPreference.setEntryValues(options.keySet().toArray(new String[0])); } private void setExportDirectorySummary() { diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index c07f12cbb..e866f2da2 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -47,6 +47,7 @@ import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.TrackFilenameGenerator; import de.dennisguse.opentracks.ui.customRecordingLayout.CsvLayoutUtils; import de.dennisguse.opentracks.ui.customRecordingLayout.Layout; +import de.dennisguse.opentracks.util.IntentDashboardUtils; import de.dennisguse.opentracks.util.TrackIconUtils; /** @@ -761,4 +762,13 @@ public class PreferencesUtils { public static void clear() { sharedPreferences.edit().clear().commit(); } + + public static void setShowOnMapFormat(final String showOnMapFormat) { + setString(R.string.show_on_map_format_key, showOnMapFormat); + } + + public static String getShowOnMapFormat() { + return getString(R.string.show_on_map_format_key, IntentDashboardUtils.PREFERENCE_ID_ASK); + } + } diff --git a/src/main/java/de/dennisguse/opentracks/settings/UserInterfaceSettingsFragment.java b/src/main/java/de/dennisguse/opentracks/settings/UserInterfaceSettingsFragment.java index d1727329d..1a6e4ae69 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/UserInterfaceSettingsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/settings/UserInterfaceSettingsFragment.java @@ -5,10 +5,15 @@ import android.content.SharedPreferences; import android.os.Bundle; import androidx.fragment.app.DialogFragment; +import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import java.util.Map; + import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.io.file.TrackFileFormat; +import de.dennisguse.opentracks.util.IntentDashboardUtils; public class UserInterfaceSettingsFragment extends PreferenceFragmentCompat { @@ -28,6 +33,8 @@ public class UserInterfaceSettingsFragment extends PreferenceFragmentCompat { startActivity(intent); return true; }); + + setShowOnMapFormatOptions(); } @Override @@ -64,4 +71,14 @@ public class UserInterfaceSettingsFragment extends PreferenceFragmentCompat { super.onDisplayPreferenceDialog(preference); } + + private void setShowOnMapFormatOptions() { + Map options = TrackFileFormat.toPreferenceIdLabelMap(getResources(), IntentDashboardUtils.SHOW_ON_MAP_TRACK_FILE_FORMATS); + options.put(IntentDashboardUtils.PREFERENCE_ID_DASHBOARD, getString(R.string.show_on_dashboard)); + options.put(IntentDashboardUtils.PREFERENCE_ID_ASK, getString(R.string.show_on_map_format_ask)); + ListPreference listPreference = findPreference(getString(R.string.show_on_map_format_key)); + listPreference.setEntries(options.values().toArray(new String[0])); + listPreference.setEntryValues(options.keySet().toArray(new String[0])); + } + } diff --git a/src/main/java/de/dennisguse/opentracks/share/ShowOnMapProxyActivity.java b/src/main/java/de/dennisguse/opentracks/share/ShowOnMapProxyActivity.java deleted file mode 100644 index efd33d93a..000000000 --- a/src/main/java/de/dennisguse/opentracks/share/ShowOnMapProxyActivity.java +++ /dev/null @@ -1,72 +0,0 @@ -package de.dennisguse.opentracks.share; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.util.Pair; - -import androidx.appcompat.app.AppCompatActivity; - -import java.util.Set; - -import de.dennisguse.opentracks.R; -import de.dennisguse.opentracks.data.ShareContentProvider; -import de.dennisguse.opentracks.data.models.Track; -import de.dennisguse.opentracks.io.file.TrackFileFormat; -import de.dennisguse.opentracks.util.IntentDashboardUtils; - -/** - * Used to convert IntentDashboardUtils.startDashboard-requests into {@link TrackFileFormat}. - */ -public abstract class ShowOnMapProxyActivity extends AppCompatActivity { - - private final TrackFileFormat trackFileFormat; - - protected ShowOnMapProxyActivity(TrackFileFormat trackFileFormat) { - this.trackFileFormat = trackFileFormat; - } - - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Set trackIds = IntentDashboardUtils.extractTrackIdsFromIntent(getIntent()); - - showTrackfileFormat(this, trackFileFormat, trackIds); - - finish(); - } - - /** - * Send intent to show tracks on a map (needs an another app) as KMZ. - * - * @param context the context - * @param trackIds the track ids - */ - private static void showTrackfileFormat(Context context, TrackFileFormat trackFileFormat, Set trackIds) { - if (trackIds.isEmpty()) { - return; - } - - Intent intent = new Intent(android.content.Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - Pair uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", trackFileFormat); - intent.setDataAndType(uriAndMime.first, uriAndMime.second); - - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - context.startActivity(Intent.createChooser(intent, context.getString(R.string.open_track_as_trackfileformat, trackFileFormat.getExtension()))); - } - - public static class KML extends ShowOnMapProxyActivity { - public KML() { - super(TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA); - } - } - - public static class GPX extends ShowOnMapProxyActivity { - public GPX() { - super(TrackFileFormat.GPX); - } - } -} \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/util/IntentDashboardUtils.java b/src/main/java/de/dennisguse/opentracks/util/IntentDashboardUtils.java index 42ebcdb07..4d1c39f5b 100644 --- a/src/main/java/de/dennisguse/opentracks/util/IntentDashboardUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/IntentDashboardUtils.java @@ -5,31 +5,45 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.util.Log; +import android.util.Pair; -import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.ContentProviderUtils; +import de.dennisguse.opentracks.data.ShareContentProvider; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.tables.MarkerColumns; import de.dennisguse.opentracks.data.tables.TrackPointsColumns; import de.dennisguse.opentracks.data.tables.TracksColumns; +import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.settings.PreferencesUtils; /** - * Create an {@link Intent} to request showing a Dashboard. + * Create an {@link Intent} to request showing tracks on a Map or a Dashboard. * The receiving {@link android.app.Activity} gets temporary access to the {@link TracksColumns} and the {@link TrackPointsColumns} (incl. update). */ public class IntentDashboardUtils { + private static final String TAG = IntentDashboardUtils.class.getSimpleName(); private static final String ACTION_DASHBOARD = "Intent.OpenTracks-Dashboard"; private static final String ACTION_DASHBOARD_PAYLOAD = ACTION_DASHBOARD + ".Payload"; + public static final TrackFileFormat[] SHOW_ON_MAP_TRACK_FILE_FORMATS = new TrackFileFormat[] { + TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES, + TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, + TrackFileFormat.GPX}; + + public static final String PREFERENCE_ID_DASHBOARD = ACTION_DASHBOARD; + public static final String PREFERENCE_ID_ASK = "ASK"; + /** * Assume "v1" if not present. */ @@ -49,24 +63,78 @@ public class IntentDashboardUtils { private static final int TRACK_URI_INDEX = 0; private static final int TRACKPOINTS_URI_INDEX = 1; private static final int MARKERS_URI_INDEX = 2; + private static final int NONE_SELECTED = -1; private IntentDashboardUtils() { } /** * Send intent to show tracks on a map (needs an another app) as resource URIs. + * Shows an AlertDialog with different format option if none is defined as preference. * * @param context the context + * @param isRecording are we currently recording? * @param trackIds the track ids */ - public static void startDashboard(Context context, boolean isRecording, Track.Id... trackIds) { - startDashboard(context, isRecording, null, null, trackIds); + public static void showTrackOnMap(Context context, boolean isRecording, Track.Id... trackIds) { + Map options = TrackFileFormat.toPreferenceIdLabelMap(context.getResources(), IntentDashboardUtils.SHOW_ON_MAP_TRACK_FILE_FORMATS); + options.put(IntentDashboardUtils.PREFERENCE_ID_DASHBOARD, context.getString(R.string.show_on_dashboard)); + final String[] optionLabels = options.values().toArray(new String[0]); + final String[] optionValues = options.keySet().toArray(new String[0]); + final AtomicInteger checkedItem = new AtomicInteger(NONE_SELECTED); + String preferenceValue = PreferencesUtils.getShowOnMapFormat(); + for (int i = 0; i < optionValues.length; i++) { + if (optionValues[i].equals(preferenceValue)) { + checkedItem.set(i); + } + } + if (checkedItem.get() == NONE_SELECTED) { + checkedItem.set(0); // set first option as default + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.select_show_on_map_behavior); + builder.setSingleChoiceItems(optionLabels, checkedItem.get(), (dialog, which) -> checkedItem.set(which)); + builder.setPositiveButton(android.R.string.ok, (dialog, which) -> onFormatSelected(context, isRecording, optionValues[checkedItem.get()], trackIds, false)); + builder.setNeutralButton(R.string.always, ((dialog, which) -> onFormatSelected(context, isRecording, optionValues[checkedItem.get()], trackIds, true))); + builder.setNegativeButton(android.R.string.cancel, null); + + AlertDialog dialog = builder.create(); + dialog.show(); + } else { + onFormatSelected(context, isRecording, preferenceValue, trackIds, true); + } + } + + /** + * A format was selected, remember if always is true and start the necessary action + * + * @param context the context + * @param isRecording are we currently recording? + * @param selectedValue the chosen format + * @param trackIds the track ids + * @param always set the selectedValue as default preference + */ + private static void onFormatSelected(final Context context, final boolean isRecording, final String selectedValue, final Track.Id[] trackIds, final boolean always) { + if (always) { + PreferencesUtils.setShowOnMapFormat(selectedValue); + } + TrackFileFormat trackFileFormat = TrackFileFormat.valueOfPreferenceId(selectedValue); + if (trackFileFormat != null) { + showTrackOnMapWithFileFormat(context, trackFileFormat, Set.of(trackIds)); + } else { + startDashboard(context, isRecording, null, null, trackIds); + } } /** * Send intent to show tracks on a map (needs an another app) as resource URIs. * By providing a targetPackage and targetClass an explicit intent can be sent, * thus bypassing the need for the user to select an app. + * + * @param context the context + * @param isRecording are we currently recording? + * @param targetPackage the target package + * @param targetClass the target class + * @param trackIds the track ids */ public static void startDashboard(Context context, boolean isRecording, String targetPackage, String targetClass, Track.Id... trackIds) { if (trackIds.length == 0) { @@ -108,16 +176,27 @@ public class IntentDashboardUtils { context.startActivity(intent); } - public static Set extractTrackIdsFromIntent(@NonNull Intent intent) { - final ArrayList uris = intent.getParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD); - final Uri tracksUri = uris.get(TRACK_URI_INDEX); - - String[] trackIdsString = ContentProviderUtils.parseTrackIdsFromUri(tracksUri); - Set trackIds = new HashSet<>(trackIdsString.length); - for (String s : trackIdsString) { - trackIds.add(new Track.Id(Long.parseLong(s))); + /** + * Send intent to show tracks on a map (needs an another app) to support specific trackFileFormat. + * + * @param context the context + * @param trackFileFormat the track file format + * @param trackIds the track ids + */ + private static void showTrackOnMapWithFileFormat(Context context, TrackFileFormat trackFileFormat, Set trackIds) { + if (trackIds.isEmpty()) { + return; } - return trackIds; + Intent intent = new Intent(android.content.Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + Pair uriAndMime = ShareContentProvider.createURI(trackIds, "SharingTrack", trackFileFormat); + intent.setDataAndType(uriAndMime.first, uriAndMime.second); + + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + context.startActivity(Intent.createChooser(intent, context.getString(R.string.open_track_as_trackfileformat, trackFileFormat.getExtension()))); } + } diff --git a/src/main/res/values/do_not_translate.xml b/src/main/res/values/do_not_translate.xml index 1cb642276..b84a8cade 100644 --- a/src/main/res/values/do_not_translate.xml +++ b/src/main/res/values/do_not_translate.xml @@ -99,4 +99,5 @@ limitations under the License. @string/waypoint_type_water_fountain @string/waypoint_type_waypoint + \ No newline at end of file diff --git a/src/main/res/values/settings.xml b/src/main/res/values/settings.xml index e18f47ef2..273c25088 100644 --- a/src/main/res/values/settings.xml +++ b/src/main/res/values/settings.xml @@ -44,6 +44,8 @@ true + showOnMapFormatKey + settingsDefaultExportDirectory instantExportEnabled false diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index d11fa5b99..ccae52a32 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -639,4 +639,9 @@ limitations under the License. %1$s crashed Share crash report Report bug + + Select \"show on map\" behavior + Ask + OpenTracks Dashboard API + Always diff --git a/src/main/res/xml/settings_user_interface.xml b/src/main/res/xml/settings_user_interface.xml index 6d251fcb7..f0d5375cd 100644 --- a/src/main/res/xml/settings_user_interface.xml +++ b/src/main/res/xml/settings_user_interface.xml @@ -43,4 +43,10 @@ android:summary="@string/settings_recording_fullscreen_on_while_recording_summary" android:title="@string/settings_recording_fullscreen_on_while_recording_title" /> + + \ No newline at end of file