offline track

This commit is contained in:
2026-06-19 12:50:42 +03:00
parent 8812cf9b40
commit d4842d4b29
3 changed files with 69 additions and 15 deletions
@@ -67,6 +67,15 @@ public class CommandPoller {
} }
} }
@Override
public void onSyncComplete(long trackId, int pointCount) {
if (pendingAckSessionId > 0 && trackId > 0) {
long sid = pendingAckSessionId;
pendingAckSessionId = -1;
executor.execute(() -> ackSession(sid, trackId));
}
}
@Override @Override
public void onError(String message) { public void onError(String message) {
Log.w(TAG, "track: " + message); Log.w(TAG, "track: " + message);
@@ -136,15 +136,40 @@ public class TrackRecorder {
} }
public void start() { public void start() {
if (recording || pendingSync) { if (recording) {
return; return;
} }
executor.execute(() -> { executor.execute(() -> {
if (pendingSync) {
syncWhenOnline();
if (pendingSync) {
notifyError(appContext.getString(R.string.track_sync_pending));
return;
}
}
if (!networkMonitor.isOnline()) { if (!networkMonitor.isOnline()) {
startLocalRecording(); startLocalRecording();
return; return;
} }
try { try {
startOnlineRecording();
} catch (Exception e) {
Log.w(TAG, "start track on server failed", e);
if (isReachabilityError(e)) {
startLocalRecording();
} else {
notifyError(e.getMessage() != null ? e.getMessage() : "start failed");
}
}
});
}
/** Retry upload of a track stopped offline. */
public void retryPendingSync() {
executor.execute(this::syncWhenOnline);
}
private void startOnlineRecording() throws Exception {
long id = serverApi.startTrack(deviceId); long id = serverApi.startTrack(deviceId);
synchronized (buffer) { synchronized (buffer) {
buffer.clear(); buffer.clear();
@@ -157,11 +182,29 @@ public class TrackRecorder {
persistState(false); persistState(false);
startTimers(); startTimers();
notifyState(); notifyState();
} catch (Exception e) {
Log.e(TAG, "start track failed", e);
notifyError(e.getMessage());
} }
});
private static boolean isReachabilityError(Throwable e) {
while (e != null) {
if (e instanceof java.net.UnknownHostException
|| e instanceof java.net.ConnectException
|| e instanceof java.net.SocketTimeoutException) {
return true;
}
String msg = e.getMessage();
if (msg != null) {
String lower = msg.toLowerCase();
if (lower.contains("unable to resolve host")
|| lower.contains("failed to connect")
|| lower.contains("timeout")
|| lower.contains("econnrefused")
|| lower.contains("network is unreachable")) {
return true;
}
}
e = e.getCause();
}
return false;
} }
private void startLocalRecording() { private void startLocalRecording() {
@@ -265,6 +308,7 @@ public class TrackRecorder {
trackId = id; trackId = id;
flushBuffer(); flushBuffer();
persistState(false); persistState(false);
notifyState();
Log.i(TAG, "promoted local track to server id " + id); Log.i(TAG, "promoted local track to server id " + id);
} catch (Exception e) { } catch (Exception e) {
Log.w(TAG, "promote local track failed", e); Log.w(TAG, "promote local track failed", e);
@@ -681,6 +681,7 @@ public class MapFragment extends Fragment {
trackRecorder.stop(); trackRecorder.stop();
} else { } else {
if (trackRecorder.hasPendingSync()) { if (trackRecorder.hasPendingSync()) {
trackRecorder.retryPendingSync();
Toast.makeText(requireContext(), R.string.track_sync_pending, Toast.LENGTH_SHORT).show(); Toast.makeText(requireContext(), R.string.track_sync_pending, Toast.LENGTH_SHORT).show();
return; return;
} }