forked from upstream-mirrors/OpenTracks
@@ -117,7 +117,19 @@ 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.
|
||||||
|
|
||||||
An overview of Bluetooth LE sensors that are known to work with OpenTracks is in [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md).
|
### API
|
||||||
|
The following functionalities by sending from an external 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 Intent to start an activity.
|
||||||
|
Package (depends on the variant installed):
|
||||||
|
* F-Droid: `de.dennisguse.opentracks`
|
||||||
|
* GooglePlay: `de.dennisguse.opentracks.playStore`
|
||||||
|
* Debug: `de.dennisguse.opentracks.debug`
|
||||||
|
* Nightly: `de.dennisguse.opentracks.nightly`
|
||||||
|
|
||||||
|
Activity:
|
||||||
|
* **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording`
|
||||||
|
|
||||||
|
* For testing via adb: `adb shell am start -n "package/activity"`
|
||||||
|
|
||||||
## Custom Dashboards (incl. map)
|
## Custom Dashboards (incl. map)
|
||||||
As of v3.3.1, OpenTracks supports custom dashboards.
|
As of v3.3.1, OpenTracks supports custom dashboards.
|
||||||
|
|||||||
@@ -69,6 +69,23 @@ limitations under the License.
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/ThemeCustom">
|
android:theme="@style/ThemeCustom">
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".publicapi.StartRecording"
|
||||||
|
android:exported="true"
|
||||||
|
android:theme="@style/SplashTheme">
|
||||||
|
<intent-filter>
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!-- <activity-->
|
||||||
|
<!-- android:name=".publicapi.StopRecording"-->
|
||||||
|
<!-- android:exported="true"-->
|
||||||
|
<!-- android:theme="@style/SplashTheme">-->
|
||||||
|
<!-- <intent-filter>-->
|
||||||
|
<!-- <category android:name="android.intent.category.DEFAULT" />-->
|
||||||
|
<!-- </intent-filter>-->
|
||||||
|
<!-- </activity>-->
|
||||||
|
|
||||||
<activity android:name=".AboutActivity" />
|
<activity android:name=".AboutActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
@@ -308,7 +325,9 @@ limitations under the License.
|
|||||||
|
|
||||||
<activity android:name=".TrackRecordedActivity" />
|
<activity android:name=".TrackRecordedActivity" />
|
||||||
|
|
||||||
<activity android:name=".TrackRecordingActivity" android:parentActivityName=".TrackListActivity">
|
<activity
|
||||||
|
android:name=".TrackRecordingActivity"
|
||||||
|
android:parentActivityName=".TrackListActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".TrackListActivity" />
|
android:value=".TrackListActivity" />
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package de.dennisguse.opentracks.publicapi;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
|
public abstract class AbstractAPIActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private final String TAG = AbstractAPIActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
private final TrackRecordingServiceConnection.Callback serviceConnectedCallback = service -> {
|
||||||
|
if (!isFinishing() && !isDestroyed()) {
|
||||||
|
execute(service);
|
||||||
|
}
|
||||||
|
if (isPostExecuteStopService()) {
|
||||||
|
AbstractAPIActivity.this.trackRecordingServiceConnection.unbindAndStop(AbstractAPIActivity.this);
|
||||||
|
} else {
|
||||||
|
AbstractAPIActivity.this.trackRecordingServiceConnection.unbind(AbstractAPIActivity.this);
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
};
|
||||||
|
|
||||||
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (PreferencesUtils.isPublicAPIenabled()) {
|
||||||
|
Log.i(TAG, "Received and trying to execute requested action.");
|
||||||
|
trackRecordingServiceConnection = new TrackRecordingServiceConnection(serviceConnectedCallback);
|
||||||
|
trackRecordingServiceConnection.startAndBind(this);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, getString(R.string.settings_public_api_disabled_toast), Toast.LENGTH_LONG).show();
|
||||||
|
Log.w(TAG, "Public API is disabled; ignoring request.");
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
trackRecordingServiceConnection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void execute(TrackRecordingService service);
|
||||||
|
|
||||||
|
protected abstract boolean isPostExecuteStopService();
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package de.dennisguse.opentracks.publicapi;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
|
||||||
|
public class StartRecording extends AbstractAPIActivity {
|
||||||
|
|
||||||
|
protected void execute(TrackRecordingService service) {
|
||||||
|
service.startNewTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isPostExecuteStopService() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package de.dennisguse.opentracks.publicapi;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
|
||||||
|
public class StopRecording extends AbstractAPIActivity {
|
||||||
|
|
||||||
|
protected void execute(TrackRecordingService service) {
|
||||||
|
service.endCurrentTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isPostExecuteStopService() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -282,7 +282,6 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
showNotification(true);
|
showNotification(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
|
||||||
public void endCurrentTrack() {
|
public void endCurrentTrack() {
|
||||||
if (!isRecording()) {
|
if (!isRecording()) {
|
||||||
Log.w(TAG, "Ignore endCurrentTrack. Not recording.");
|
Log.w(TAG, "Ignore endCurrentTrack. Not recording.");
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import android.util.Log;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -179,6 +178,10 @@ public class PreferencesUtils {
|
|||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPublicAPIenabled() {
|
||||||
|
return getBoolean(R.string.publicapi_enabled_key, resources.getBoolean(R.bool.publicapi_enabled_default));
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isMetricUnits() {
|
public static boolean isMetricUnits() {
|
||||||
final String STATS_UNIT = resources.getString(R.string.stats_units_default);
|
final String STATS_UNIT = resources.getString(R.string.stats_units_default);
|
||||||
return STATS_UNIT.equals(getString(R.string.stats_units_key, STATS_UNIT));
|
return STATS_UNIT.equals(getString(R.string.stats_units_key, STATS_UNIT));
|
||||||
|
|||||||
@@ -291,6 +291,9 @@
|
|||||||
<string name="import_prevent_reimport_key" translatable="false">preventReimportTrackKey</string>
|
<string name="import_prevent_reimport_key" translatable="false">preventReimportTrackKey</string>
|
||||||
<bool name="import_prevent_reimport_default">true</bool>
|
<bool name="import_prevent_reimport_default">true</bool>
|
||||||
|
|
||||||
|
<string name="publicapi_enabled_key" translatable="false">apiEnabledKey</string>
|
||||||
|
<bool name="publicapi_enabled_default">false</bool>
|
||||||
|
|
||||||
<integer name="buttonDelayMillis">1500</integer>
|
<integer name="buttonDelayMillis">1500</integer>
|
||||||
|
|
||||||
<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
|
<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
|
||||||
|
|||||||
@@ -445,6 +445,12 @@ limitations under the License.
|
|||||||
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
||||||
<string name="settings_stats_units_title">Preferred units</string>
|
<string name="settings_stats_units_title">Preferred units</string>
|
||||||
|
|
||||||
|
<!-- Settings public api -->
|
||||||
|
<string name="settings_public_api_enabled_title">Public API</string>
|
||||||
|
<string name="settings_public_api_enabled_summary_on">Other installed applications can start or stop recordings.</string>
|
||||||
|
<string name="settings_public_api_enabled_summary_off">Only OpenTracks can start and stop recordings.</string>
|
||||||
|
<string name="settings_public_api_disabled_toast">OpenTracks Public API is disabled: it can be enabled in the settings.</string>
|
||||||
|
|
||||||
<!-- Settings import/export -->
|
<!-- Settings import/export -->
|
||||||
<string name="settings_import_section">Import</string>
|
<string name="settings_import_section">Import</string>
|
||||||
<string name="settings_export_section">Export</string>
|
<string name="settings_export_section">Export</string>
|
||||||
|
|||||||
@@ -4,56 +4,63 @@
|
|||||||
android:title="@string/menu_settings">
|
android:title="@string/menu_settings">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_units"
|
||||||
android:key="@string/settings_defaults_key"
|
android:key="@string/settings_defaults_key"
|
||||||
android:title="@string/settings_defaults_title"
|
|
||||||
android:summary="@string/settings_defaults_summary"
|
android:summary="@string/settings_defaults_summary"
|
||||||
android:icon="@drawable/ic_units" />
|
android:title="@string/settings_defaults_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_ui"
|
||||||
android:key="@string/settings_ui_key"
|
android:key="@string/settings_ui_key"
|
||||||
android:title="@string/settings_ui_title"
|
|
||||||
android:summary="@string/settings_ui_summary"
|
android:summary="@string/settings_ui_summary"
|
||||||
android:icon="@drawable/ic_ui" />
|
android:title="@string/settings_ui_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_baseline_satellite_alt_24"
|
||||||
android:key="@string/settings_gps_key"
|
android:key="@string/settings_gps_key"
|
||||||
android:title="@string/settings_gps_title"
|
|
||||||
android:summary="@string/settings_gps_summary"
|
android:summary="@string/settings_gps_summary"
|
||||||
android:icon="@drawable/ic_baseline_satellite_alt_24" />
|
android:title="@string/settings_gps_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_baseline_sensors_24"
|
||||||
android:key="@string/settings_sensors_key"
|
android:key="@string/settings_sensors_key"
|
||||||
android:title="@string/settings_sensors_title"
|
|
||||||
android:summary="@string/settings_sensors_summary"
|
android:summary="@string/settings_sensors_summary"
|
||||||
android:icon="@drawable/ic_baseline_sensors_24" />
|
android:title="@string/settings_sensors_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_baseline_volume_up_24"
|
||||||
android:key="@string/settings_announcements_key"
|
android:key="@string/settings_announcements_key"
|
||||||
android:title="@string/settings_announcements_title"
|
|
||||||
android:summary="@string/settings_announcements_summary"
|
android:summary="@string/settings_announcements_summary"
|
||||||
android:icon="@drawable/ic_baseline_volume_up_24" />
|
android:title="@string/settings_announcements_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_baseline_import_export_24"
|
||||||
android:key="@string/settings_import_export_key"
|
android:key="@string/settings_import_export_key"
|
||||||
android:title="@string/settings_import_export_title"
|
|
||||||
android:summary="@string/settings_import_export_summary"
|
android:summary="@string/settings_import_export_summary"
|
||||||
android:icon="@drawable/ic_baseline_import_export_24" />
|
android:title="@string/settings_import_export_title" />
|
||||||
|
|
||||||
<de.dennisguse.opentracks.settings.ResetDialogPreference
|
<de.dennisguse.opentracks.settings.ResetDialogPreference
|
||||||
android:dialogMessage="@string/settings_reset_confirm_message"
|
android:dialogMessage="@string/settings_reset_confirm_message"
|
||||||
android:dialogTitle="@string/settings_reset_confirm_title"
|
android:dialogTitle="@string/settings_reset_confirm_title"
|
||||||
|
android:icon="@drawable/ic_baseline_autorenew_24"
|
||||||
android:key="@string/settings_reset_key"
|
android:key="@string/settings_reset_key"
|
||||||
android:negativeButtonText="@android:string/cancel"
|
android:negativeButtonText="@android:string/cancel"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:positiveButtonText="@android:string/ok"
|
android:positiveButtonText="@android:string/ok"
|
||||||
android:title="@string/settings_all_reset"
|
|
||||||
android:summary="@string/settings_reset_summary"
|
android:summary="@string/settings_reset_summary"
|
||||||
android:icon="@drawable/ic_baseline_autorenew_24"/>
|
android:title="@string/settings_all_reset" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:title="@string/settings_public_api_enabled_title"
|
||||||
|
android:summaryOn="@string/settings_public_api_enabled_summary_on"
|
||||||
|
android:summaryOff="@string/settings_public_api_enabled_summary_off"
|
||||||
|
android:defaultValue="@bool/publicapi_enabled_default"
|
||||||
|
android:key="@string/publicapi_enabled_key" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:icon="@drawable/ic_baseline_info_24"
|
||||||
android:key="@string/settings_open_tracks_key"
|
android:key="@string/settings_open_tracks_key"
|
||||||
android:title="@string/settings_open_tracks_title"
|
|
||||||
android:summary="@string/settings_open_tracks_summary"
|
android:summary="@string/settings_open_tracks_summary"
|
||||||
android:icon="@drawable/ic_baseline_info_24" />
|
android:title="@string/settings_open_tracks_title" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|||||||
Reference in New Issue
Block a user