diff --git a/README.md b/README.md index 3f803816..84b4f229 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,13 @@ All scripts located in: - Data sync over WiFi/mobile - Edit advanced constants +## Trajectory Files + +Trajectory recordings are stored as JSON files named `trajectory_.txt`. +The timestamp follows `dd-MM-yy-HH-mm-ss`. Files are written and read via the +`TrajectoryIO` helper which converts between the protobuf `Traj.Trajectory` +and its JSON representation. + ## 🧩 Common Issues & Fixes | Issue | Fix | diff --git a/app/src/main/java/com/openpositioning/PositionMe/data/local/FileRepository.java b/app/src/main/java/com/openpositioning/PositionMe/data/local/FileRepository.java new file mode 100644 index 00000000..069175f2 --- /dev/null +++ b/app/src/main/java/com/openpositioning/PositionMe/data/local/FileRepository.java @@ -0,0 +1,63 @@ +package com.openpositioning.PositionMe.data.local; + +import android.content.Context; +import android.os.Build; +import android.os.Environment; +import android.util.Log; + +import com.openpositioning.PositionMe.Traj; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Simple repository for persisting {@link Traj.Trajectory} objects to the app's + * private storage. The data is written using {@link TrajectoryIO}. + */ +public class FileRepository { + private static final String TAG = "FileRepository"; + private final Context context; + + public FileRepository(Context context) { + this.context = context.getApplicationContext(); + } + + /** + * Save the trajectory to the app-specific documents directory. + * + * @param trajectory trajectory to persist + * @return resulting file or {@code null} if failed + */ + public File saveTrajectory(Traj.Trajectory trajectory) { + File dir; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + dir = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS); + if (dir == null) { + dir = context.getFilesDir(); + } + } else { + dir = context.getFilesDir(); + } + if (dir != null && !dir.exists()) { + dir.mkdirs(); + } + String time = new SimpleDateFormat("dd-MM-yy-HH-mm-ss").format(new Date()); + File file = new File(dir, "trajectory_" + time + ".txt"); + try { + TrajectoryIO.writeTrajectory(file, trajectory); + Log.i(TAG, "Trajectory written to: " + file.getAbsolutePath()); + return file; + } catch (Exception e) { + Log.e(TAG, "Failed to save trajectory", e); + return null; + } + } + + /** + * Load a trajectory from a file. + */ + public Traj.Trajectory readTrajectory(File file) throws Exception { + return TrajectoryIO.readTrajectory(file); + } +} diff --git a/app/src/main/java/com/openpositioning/PositionMe/data/local/TrajectoryIO.java b/app/src/main/java/com/openpositioning/PositionMe/data/local/TrajectoryIO.java new file mode 100644 index 00000000..8c261674 --- /dev/null +++ b/app/src/main/java/com/openpositioning/PositionMe/data/local/TrajectoryIO.java @@ -0,0 +1,47 @@ +package com.openpositioning.PositionMe.data.local; + +import com.google.protobuf.util.JsonFormat; +import com.openpositioning.PositionMe.Traj; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; + +/** + * Utility class for reading and writing {@link Traj.Trajectory} files. + *

+ * The trajectories are stored as JSON text files. Use + * {@link #writeTrajectory(File, Traj.Trajectory)} to persist a trajectory and + * {@link #readTrajectory(File)} to load it back. + */ +public class TrajectoryIO { + + /** + * Writes the given trajectory to a file in JSON format. + * + * @param file destination file + * @param traj trajectory to write + * @throws IOException if writing fails + */ + public static void writeTrajectory(File file, Traj.Trajectory traj) throws IOException { + try (FileWriter writer = new FileWriter(file)) { + writer.write(JsonFormat.printer().print(traj)); + writer.flush(); + } + } + + /** + * Reads a trajectory from a JSON file. + * + * @param file source file + * @return parsed trajectory + * @throws IOException if reading fails + */ + public static Traj.Trajectory readTrajectory(File file) throws IOException { + String json = new String(Files.readAllBytes(file.toPath())); + Traj.Trajectory.Builder builder = Traj.Trajectory.newBuilder(); + JsonFormat.parser().merge(json, builder); + return builder.build(); + } +} diff --git a/app/src/main/java/com/openpositioning/PositionMe/data/remote/ServerCommunications.java b/app/src/main/java/com/openpositioning/PositionMe/data/remote/ServerCommunications.java index 7f7e74b2..f83cac45 100644 --- a/app/src/main/java/com/openpositioning/PositionMe/data/remote/ServerCommunications.java +++ b/app/src/main/java/com/openpositioning/PositionMe/data/remote/ServerCommunications.java @@ -28,6 +28,7 @@ import com.google.protobuf.util.JsonFormat; import com.openpositioning.PositionMe.BuildConfig; import com.openpositioning.PositionMe.Traj; +import com.openpositioning.PositionMe.data.local.TrajectoryIO; import com.openpositioning.PositionMe.presentation.fragment.FilesFragment; import com.openpositioning.PositionMe.presentation.activity.MainActivity; import com.openpositioning.PositionMe.sensors.Observable; @@ -539,10 +540,8 @@ public void onResponse(Call call, Response response) throws IOException { } File file = new File(appSpecificDownloads, fileName); - try (FileWriter fileWriter = new FileWriter(file)) { - String receivedTrajectoryString = JsonFormat.printer().print(receivedTrajectory); - fileWriter.write(receivedTrajectoryString); - fileWriter.flush(); + try { + TrajectoryIO.writeTrajectory(file, receivedTrajectory); System.err.println("Received trajectory stored in: " + file.getAbsolutePath()); } catch (IOException ee) { System.err.println("Trajectory download failed"); diff --git a/app/src/main/java/com/openpositioning/PositionMe/sensors/SensorFusion.java b/app/src/main/java/com/openpositioning/PositionMe/sensors/SensorFusion.java index 1e14e5eb..ac846779 100644 --- a/app/src/main/java/com/openpositioning/PositionMe/sensors/SensorFusion.java +++ b/app/src/main/java/com/openpositioning/PositionMe/sensors/SensorFusion.java @@ -29,6 +29,7 @@ import com.openpositioning.PositionMe.utils.PdrProcessing; import com.openpositioning.PositionMe.data.remote.ServerCommunications; import com.openpositioning.PositionMe.Traj; +import com.openpositioning.PositionMe.data.local.FileRepository; import com.openpositioning.PositionMe.presentation.fragment.SettingsFragment; import com.openpositioning.PositionMe.domain.EKF; @@ -1322,6 +1323,9 @@ public void setTrajectoryMapFragment(com.openpositioning.PositionMe.presentation public void sendTrajectoryToCloud() { // Build object Traj.Trajectory sentTrajectory = trajectory.build(); + // Persist locally + FileRepository repo = new FileRepository(appContext); + repo.saveTrajectory(sentTrajectory); // Pass object to communications object this.serverCommunications.sendTrajectory(sentTrajectory); }