diff --git a/README.md b/README.md index 0310c367a..5602a7555 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ The API can be invoked by sending an explicit Intent to start an activity. `Class`: * **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording` +* **Start a recording:** `de.dennisguse.opentracks.publicapi.StopRecording` For testing via adb: `adb shell am start -n "package/class"` diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index c87033f84..4726f5997 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -77,14 +77,14 @@ limitations under the License. - - - - - - - - + + + + + diff --git a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java index 1e1c4382e..e7683fc73 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.database.Cursor; -import android.graphics.Color; import android.graphics.drawable.AnimatedVectorDrawable; import android.location.LocationManager; import android.os.Bundle; @@ -139,7 +138,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co private MenuItem searchMenuItem; private MenuItem startGpsMenuItem; - private final TrackRecordingServiceConnection.Callback bindChangedCallback = service -> { + private final TrackRecordingServiceConnection.Callback bindChangedCallback = (service, unused) -> { service.getRecordingStatusObservable() .observe(TrackListActivity.this, this::onRecordingStatusChanged); @@ -167,16 +166,15 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback); viewBinding.trackList.setEmptyView(viewBinding.trackListEmptyView); - viewBinding.trackList.setOnItemClickListener((parent, view, position, trackId) -> { - if (recordingStatus.isRecording() && trackId == recordingStatus.getTrackId().getId()) { + viewBinding.trackList.setOnItemClickListener((parent, view, position, trackIdId) -> { + Track.Id trackId = new Track.Id(trackIdId); + Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class) + .putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, trackId); + if (recordingStatus.isRecording() && trackId.equals(recordingStatus.getTrackId())) { // Is recording -> open record activity. - Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class) - .putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId)); startActivity(newIntent); } else { // Not recording -> open detail activity. - Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class) - .putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId)); ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation( this, new Pair<>(view.findViewById(R.id.list_item_icon), TrackRecordedActivity.VIEW_TRACK_ICON)); @@ -230,8 +228,15 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co // Not Recording -> Recording updateGpsMenuItem(false, true); - Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class); - startActivity(newIntent); + new TrackRecordingServiceConnection((service, connection) -> { + Track.Id trackId = service.startNewTrack(); + + Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class); + newIntent.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, trackId); + startActivity(newIntent); + + connection.unbind(this); + }).startAndBind(this); }); viewBinding.trackListFabAction.setOnLongClickListener((view) -> { if (!recordingStatus.isRecording()) { diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java index c0526bbed..db0073335 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java @@ -79,7 +79,7 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement private TrackRecordingServiceConnection trackRecordingServiceConnection; - private final TrackRecordingServiceConnection.Callback bindCallback = service -> service.getRecordingStatusObservable() + private final TrackRecordingServiceConnection.Callback bindCallback = (service, unused) -> service.getRecordingStatusObservable() .observe(TrackRecordedActivity.this, this::onRecordingStatusChanged); @Override @@ -203,11 +203,17 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement } if (item.getItemId() == R.id.track_detail_resume_track) { - Intent newIntent = IntentUtils.newIntent(TrackRecordedActivity.this, TrackRecordingActivity.class) - .putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, trackId); - startActivity(newIntent); - overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); - finish(); + new TrackRecordingServiceConnection((service, connection) -> { + service.resumeTrack(trackId); + + Intent newIntent = IntentUtils.newIntent(TrackRecordedActivity.this, TrackRecordingActivity.class) + .putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, trackId); + startActivity(newIntent); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + + connection.unbind(this); + finish(); + }).startAndBind(this); return true; } diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java index b64bf85be..3871ba042 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java @@ -57,8 +57,6 @@ import de.dennisguse.opentracks.util.TrackUtils; * @author Leif Hendrik Wilden * @author Rodrigo Damazio */ -//NOTE: This activity does NOT react to preference changes of R.string.recording_track_id_key. -//This mode of communication should be removed anyhow. public class TrackRecordingActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, TrackDataHubInterface { public static final String EXTRA_TRACK_ID = "track_id"; @@ -76,13 +74,11 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc private TrackRecordingBinding viewBinding; - // Initialized from Intent; if a new track recording is started, a new TrackId will be provided by TrackRecordingService - @Deprecated private Track.Id trackId; private RecordingStatus recordingStatus = TrackRecordingService.STATUS_DEFAULT; - private final TrackRecordingServiceConnection.Callback bindChangedCallback = service -> { + private final TrackRecordingServiceConnection.Callback bindChangedCallback = (service, unused) -> { service.getRecordingStatusObservable() .observe(TrackRecordingActivity.this, this::onRecordingStatusChanged); @@ -90,18 +86,12 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc .observe(TrackRecordingActivity.this, this::onGpsStatusChanged); if (!service.isRecording()) { - if (trackId == null) { - // trackId isn't initialized -> leads a new recording. - trackId = service.startNewTrack(); - } else { - // trackId is initialized -> resumes the track. - service.resumeTrack(trackId); - } - - // A recording track is on. - trackDataHub.loadTrack(trackId); - trackDataHub.setRecordingStatus(recordingStatus); + finish(); + return; } + + trackDataHub.loadTrack(trackId); + trackDataHub.setRecordingStatus(recordingStatus); }; private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> { @@ -123,17 +113,14 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); contentProviderUtils = new ContentProviderUtils(this); - trackId = null; - if (savedInstanceState != null) { - //Activity was recreated. - trackId = savedInstanceState.getParcelable(EXTRA_TRACK_ID); - } else { - // Resume a track - trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID); - if (trackId != null && contentProviderUtils.getTrack(trackId) == null) { - Log.w(TAG, "TrackId does not exists; cannot continue the recording."); - finish(); - } + + trackId = getIntent().getParcelableExtra(EXTRA_TRACK_ID); + if (trackId == null) { + throw new RuntimeException("TrackId is mandatory"); + } + if (contentProviderUtils.getTrack(trackId) == null) { + Log.w(TAG, "TrackId does not exists; cannot continue the recording."); + finish(); } trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback); @@ -240,7 +227,6 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(CURRENT_TAB_TAG_KEY, viewBinding.trackDetailActivityViewPager.getCurrentItem()); - outState.putParcelable(EXTRA_TRACK_ID, trackId); } @Override @@ -377,6 +363,9 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc } private void onRecordingStatusChanged(RecordingStatus status) { + if (!status.isRecording()) { + finish(); + } recordingStatus = status; trackDataHub.setRecordingStatus(recordingStatus); @@ -415,7 +404,8 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc .make(viewBinding.trackRecordingCoordinatorLayout, getString(R.string.gps_recording_status, getString(gpsStatusValue.message), getString(R.string.gps_recording_without_signal)), Snackbar.LENGTH_INDEFINITE) - .setAction(getString(R.string.generic_dismiss), v -> {}); + .setAction(getString(R.string.generic_dismiss), v -> { + }); snackbar.show(); } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index a0de16c8b..c8d1c1f56 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -77,7 +77,7 @@ public class StatisticsRecordingFragment extends Fragment { } }; - private final TrackRecordingServiceConnection.Callback bindChangedCallback = service -> { + private final TrackRecordingServiceConnection.Callback bindChangedCallback = (service, unused) -> { service.getRecordingDataObservable() .observe(StatisticsRecordingFragment.this, this::onRecordingDataChanged); }; diff --git a/src/main/java/de/dennisguse/opentracks/publicapi/AbstractAPIActivity.java b/src/main/java/de/dennisguse/opentracks/publicapi/AbstractAPIActivity.java index 153a95311..6d47fd76e 100644 --- a/src/main/java/de/dennisguse/opentracks/publicapi/AbstractAPIActivity.java +++ b/src/main/java/de/dennisguse/opentracks/publicapi/AbstractAPIActivity.java @@ -16,27 +16,25 @@ public abstract class AbstractAPIActivity extends AppCompatActivity { private final String TAG = AbstractAPIActivity.class.getSimpleName(); - private final TrackRecordingServiceConnection.Callback serviceConnectedCallback = service -> { + private final TrackRecordingServiceConnection.Callback serviceConnectedCallback = (service, connection) -> { if (!isFinishing() && !isDestroyed()) { execute(service); } if (isPostExecuteStopService()) { - AbstractAPIActivity.this.trackRecordingServiceConnection.unbindAndStop(AbstractAPIActivity.this); + connection.unbindAndStop(AbstractAPIActivity.this); } else { - AbstractAPIActivity.this.trackRecordingServiceConnection.unbind(AbstractAPIActivity.this); + connection.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); + new TrackRecordingServiceConnection(serviceConnectedCallback) + .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."); @@ -44,12 +42,6 @@ public abstract class AbstractAPIActivity extends AppCompatActivity { } } - @Override - protected void onDestroy() { - super.onDestroy(); - trackRecordingServiceConnection = null; - } - protected abstract void execute(TrackRecordingService service); protected abstract boolean isPostExecuteStopService(); diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java index 360679482..ee7c20254 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java @@ -92,15 +92,10 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death return; } if (callback != null) { - callback.onConnected(trackRecordingService); + callback.onConnected(trackRecordingService, this); } } - /** - * Resumes the track recording service connection. - * - * @param context the context - */ public void startConnection(@NonNull Context context) { if (trackRecordingService != null) { // Service is already started and bound. @@ -115,6 +110,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death /** * Unbinds the service (but leave it running). */ + //TODO This is often called for one-shot operations and should be refactored as unbinding is required. public void unbind(Context context) { try { context.unbindService(this); @@ -141,7 +137,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death trackRecordingService = value; if (callback != null) { if (value != null) { - callback.onConnected(value); + callback.onConnected(value, this); } else { callback.onDisconnected(); } @@ -214,7 +210,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death } public interface Callback { - void onConnected(TrackRecordingService service); + void onConnected(TrackRecordingService service, TrackRecordingServiceConnection connection); default void onDisconnected() { } diff --git a/src/main/java/de/dennisguse/opentracks/settings/MainSettingsFragment.java b/src/main/java/de/dennisguse/opentracks/settings/MainSettingsFragment.java index 7913f5548..2a023d36e 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/MainSettingsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/settings/MainSettingsFragment.java @@ -18,7 +18,7 @@ public class MainSettingsFragment extends PreferenceFragmentCompat { private RecordingStatus recordingStatus = TrackRecordingService.STATUS_DEFAULT; private TrackRecordingServiceConnection trackRecordingServiceConnection; private final TrackRecordingServiceConnection.Callback bindServiceCallback = - service -> service.getRecordingStatusObservable() + (service, unused) -> service.getRecordingStatusObservable() .observe(MainSettingsFragment.this, this::onRecordingStatusChanged); @Override diff --git a/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerListActivity.java b/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerListActivity.java index 5bc0c2a85..eadcec138 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerListActivity.java @@ -71,7 +71,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker private TrackRecordingServiceConnection trackRecordingServiceConnection; - private final TrackRecordingServiceConnection.Callback bindCallback = service -> service.getRecordingStatusObservable() + private final TrackRecordingServiceConnection.Callback bindCallback = (service, unused) -> service.getRecordingStatusObservable() .observe(MarkerListActivity.this, this::onRecordingStatusChanged); // Callback when an item is selected in the contextual action mode