forked from upstream-mirrors/OpenTracks
Public API: allow setting track properties (name, category, description) on StartRecording.
Fixes #1282.
This commit is contained in:
@@ -95,7 +95,7 @@ OpenTracks can be used with [Gadgetbridge](https://www.gadgetbridge.org/):
|
|||||||
__Only required permission:__
|
__Only required permission:__
|
||||||
* _ACCESS_FINE_LOCATION_: required to use the GPS.
|
* _ACCESS_FINE_LOCATION_: required to use the GPS.
|
||||||
|
|
||||||
### API
|
### Public API
|
||||||
|
|
||||||
OpenTracks includes an API for starting/stopping recording by another installed application (e.g., [Automate](https://llamalab.com/automate/), [Tasker](https://tasker.joaoapps.com), or [Easer](https://github.com/renyuneyun/Easer)).
|
OpenTracks includes an API for starting/stopping recording by another installed application (e.g., [Automate](https://llamalab.com/automate/), [Tasker](https://tasker.joaoapps.com), or [Easer](https://github.com/renyuneyun/Easer)).
|
||||||
The API can be invoked by sending an explicit Intent to start an activity.
|
The API can be invoked by sending an explicit Intent to start an activity.
|
||||||
@@ -107,20 +107,37 @@ The API can be invoked by sending an explicit Intent to start an activity.
|
|||||||
* Nightly: `de.dennisguse.opentracks.nightly`
|
* Nightly: `de.dennisguse.opentracks.nightly`
|
||||||
|
|
||||||
`Class`:
|
`Class`:
|
||||||
|
|
||||||
* **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording`
|
* **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording`
|
||||||
* **Stop a recording:** `de.dennisguse.opentracks.publicapi.StopRecording`
|
* **Stop a recording:** `de.dennisguse.opentracks.publicapi.StopRecording`
|
||||||
|
|
||||||
For testing via adb: `adb shell am start -n "package/class"`
|
For testing via adb: `adb shell am start -n "package/class"`
|
||||||
|
|
||||||
The Start/Stop API is disabled by default to protect the user's privacy, but it can easily be enabled in the settings.
|
`StartRecording` supports the following parameters:
|
||||||
|
|
||||||
## Custom Dashboards (incl. map)
|
* Set track data: `TRACK_NAME`, `TRACK_CATEGORY`, and `TRACK_DESCRIPTION`
|
||||||
As of v3.3.1, OpenTracks supports custom dashboards for displaying previously recorded and live tracks.
|
* Send recorded data to another application via _Dashboard API_: `STATS_TARGET_PACKAGE`
|
||||||
|
and `STATS_TARGET_CLASS`
|
||||||
|
|
||||||
The reference implementation is [OSMDashboard](https://github.com/OpenTracksApp/OSMDashboard), which presents an OpenStreetMap map (showing the current track, incl. updates). The Dashboard API is also used by [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) for displaying live track statistics on supported wearables.
|
The Public API is disabled by default to protect the user's privacy, but it can easily be enabled in
|
||||||
|
the settings.
|
||||||
|
|
||||||
Alternatively, recorded tracks can be shared as KMZ/GPX with installed applications (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand)).
|
__IMPORTANT__: triggering `StartRecording` does not check if Android permissions (location or
|
||||||
However, this is rather slow and does not provide updates while recording.
|
Bluetooth) were granted. If they are not granted`
|
||||||
|
|
||||||
|
## Dashboard API (incl. map)
|
||||||
|
|
||||||
|
As of v3.3.1, OpenTracks supports custom dashboards for displaying previously recorded and live
|
||||||
|
tracks.
|
||||||
|
|
||||||
|
The reference implementation is [OSMDashboard](https://github.com/OpenTracksApp/OSMDashboard), which
|
||||||
|
presents an OpenStreetMap map (showing the current track, incl. updates). The Dashboard API is also
|
||||||
|
used by [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) for displaying live track
|
||||||
|
statistics on supported wearables.
|
||||||
|
|
||||||
|
Alternatively, recorded tracks can be shared as KMZ/GPX with installed applications (
|
||||||
|
e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand)). However, this is rather
|
||||||
|
slow and does not provide updates while recording.
|
||||||
|
|
||||||
The developer documentation is in [README_API.md](README_API.md).
|
The developer documentation is in [README_API.md](README_API.md).
|
||||||
|
|
||||||
|
|||||||
@@ -2,26 +2,57 @@ package de.dennisguse.opentracks.publicapi;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.data.models.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
||||||
|
import de.dennisguse.opentracks.util.TrackUtils;
|
||||||
|
|
||||||
public class StartRecording extends AbstractAPIActivity {
|
public class StartRecording extends AbstractAPIActivity {
|
||||||
|
|
||||||
|
public static final String EXTRA_TRACK_NAME = "TRACK_NAME";
|
||||||
|
public static final String EXTRA_TRACK_CATEGORY = "TRACK_CATEGORY";
|
||||||
|
public static final String EXTRA_TRACK_DESCRIPTION = "TRACK_DESCRIPTION";
|
||||||
|
|
||||||
|
public static final String EXTRA_STATS_TARGET_PACKAGE = "STATS_TARGET_PACKAGE";
|
||||||
|
public static final String EXTRA_STATS_TARGET_CLASS = "STATS_TARGET_CLASS";
|
||||||
|
|
||||||
private static final String TAG = StartRecording.class.getSimpleName();
|
private static final String TAG = StartRecording.class.getSimpleName();
|
||||||
|
|
||||||
protected void execute(TrackRecordingService service) {
|
protected void execute(TrackRecordingService service) {
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
if ((trackId != null) && (PreferencesUtils.isPublicAPIDashboardEnabled())) {
|
if (trackId != null) {
|
||||||
Bundle bundle = getIntent().getExtras();
|
Bundle bundle = getIntent().getExtras();
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
String targetPackage = bundle.getString("STATS_TARGET_PACKAGE", null);
|
updateTrackMetadata(trackId, bundle);
|
||||||
String targetClass = bundle.getString("STATS_TARGET_CLASS", null);
|
|
||||||
IntentDashboardUtils.startDashboard(this, true, targetPackage, targetClass, trackId);
|
if (PreferencesUtils.isPublicAPIDashboardEnabled()) {
|
||||||
|
startDashboardAPI(trackId, bundle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateTrackMetadata(@NonNull Track.Id trackId, @NonNull Bundle bundle) {
|
||||||
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
||||||
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
|
TrackUtils.updateTrack(this, track, bundle.getString(EXTRA_TRACK_NAME, null),
|
||||||
|
bundle.getString(EXTRA_TRACK_CATEGORY, null), bundle.getString(EXTRA_TRACK_DESCRIPTION, null),
|
||||||
|
contentProviderUtils);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startDashboardAPI(@NonNull Track.Id trackId, @NonNull Bundle bundle) {
|
||||||
|
String targetPackage = bundle.getString(EXTRA_STATS_TARGET_PACKAGE, null);
|
||||||
|
String targetClass = bundle.getString(EXTRA_STATS_TARGET_CLASS, null);
|
||||||
|
if (targetClass != null && targetPackage != null) {
|
||||||
|
IntentDashboardUtils.startDashboard(this, true, targetPackage, targetClass, trackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isPostExecuteStopService() {
|
protected boolean isPostExecuteStopService() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.util.Log;
|
|||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -138,7 +139,7 @@ public class IntentDashboardUtils {
|
|||||||
* @param targetClass the target class
|
* @param targetClass the target class
|
||||||
* @param trackIds the track ids
|
* @param trackIds the track ids
|
||||||
*/
|
*/
|
||||||
public static void startDashboard(Context context, boolean isRecording, String targetPackage, String targetClass, Track.Id... trackIds) {
|
public static void startDashboard(Context context, boolean isRecording, @Nullable String targetPackage, @Nullable String targetClass, Track.Id... trackIds) {
|
||||||
if (trackIds.length == 0) {
|
if (trackIds.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -168,7 +169,7 @@ public class IntentDashboardUtils {
|
|||||||
clipData.addItem(new ClipData.Item(uris.get(MARKERS_URI_INDEX)));
|
clipData.addItem(new ClipData.Item(uris.get(MARKERS_URI_INDEX)));
|
||||||
intent.setClipData(clipData);
|
intent.setClipData(clipData);
|
||||||
|
|
||||||
if ((targetPackage != null) && (targetClass != null)) {
|
if (targetPackage != null && targetClass != null) {
|
||||||
Log.i(TAG, "Starting dashboard activity with explicit intent (package=" + targetPackage + ", class=" + targetClass + ")");
|
Log.i(TAG, "Starting dashboard activity with explicit intent (package=" + targetPackage + ", class=" + targetClass + ")");
|
||||||
intent.setClassName(targetPackage, targetClass);
|
intent.setClassName(targetPackage, targetClass);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user