diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java index 463633d..87dc742 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java @@ -1,6 +1,5 @@ package com.ridgebotics.ridgescout.ui.settings; -import static android.view.View.VISIBLE; import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.VERTICAL; import static androidx.navigation.fragment.FragmentKt.findNavController; @@ -32,13 +31,9 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.CheckBox; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ScrollView; -import android.widget.TableLayout; -import android.widget.TableRow; import android.widget.TextView; import androidx.annotation.NonNull; @@ -58,9 +53,7 @@ import com.ridgebotics.ridgescout.ui.views.TallyCounterView; import com.ridgebotics.ridgescout.utility.AlertManager; import com.ridgebotics.ridgescout.utility.DataManager; import com.ridgebotics.ridgescout.utility.FileEditor; -import com.ridgebotics.ridgescout.utility.SettingsManager; - -import org.w3c.dom.Text; +import com.ridgebotics.ridgescout.utility.ToDelete; import java.util.ArrayList; import java.util.Arrays; @@ -98,17 +91,10 @@ public class SettingsFragment extends Fragment { ButtonSettingsItem corruptButton = new ButtonSettingsItem(); corruptButton.addButton("find corrupted files", view -> { - new Thread(() -> { - AlertManager.startLoading("Loading files..."); - List filenames = FileEditor.findCorruptedFiles(); - AlertManager.stopLoading(); - getActivity().runOnUiThread(() -> { - deleteFiles(filenames, true); - }); - }).start(); + ToDelete.findCorruptedFiles(getContext()); }); corruptButton.addButton("delete files", view -> { - deleteFiles(Arrays.asList(FileEditor.getFiles()), false); + ToDelete.deleteFiles(getContext(), Arrays.asList(FileEditor.getFiles()), false); }); // corruptButton.setEnabled(!getEVCode().equals("unset")); @@ -264,35 +250,7 @@ public class SettingsFragment extends Fragment { alert.create().show(); } - private void deleteFiles(List files, boolean defaultOption) { - ScrollView sv = new ScrollView(getContext()); - LinearLayout ll = new LinearLayout(getContext()); - ll.setOrientation(VERTICAL); - sv.addView(ll); - CheckBox[] checkboxes = new CheckBox[files.size()]; - - for(int i =0; i < files.size(); i++){ - CheckBox cb = new CheckBox(getContext()); - cb.setText(files.get(i)); - cb.setChecked(defaultOption); - ll.addView(cb); - checkboxes[i] = cb; - } - - - AlertDialog.Builder alert = new AlertDialog.Builder(getContext()); - alert.setTitle("Delete files"); - alert.setView(sv); - alert.setNeutralButton("Cancel", null); -// alert.setPositiveButton("Save", (dialogInterface, i) -> { -// DataManager.scoutNotice = editText.getText().toString(); -// DataManager.save_scout_notice(); -// }); - alert.setCancelable(false); - - alert.create().show(); - } private TextView createText(String title) { TextView tv = new TextView(getContext()); @@ -311,7 +269,7 @@ public class SettingsFragment extends Fragment { ll.addView(createText("Package: " + pInfo.packageName)); ll.addView(createText("Version: " + pInfo.versionName)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - ll.addView(createText("Signature: " + (pInfo.signingInfo != null ? pInfo.signingInfo.toString() : "None"))); + ll.addView(createText("Signature: " + (pInfo.signingInfo != null ? "True" : "False"))); } } catch (PackageManager.NameNotFoundException e) { diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java index 64b77ea..1596224 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FileSelectorFragment.java @@ -49,7 +49,10 @@ public class FileSelectorFragment extends Fragment { meta_string_array = new String[]{ "matches.fields", "pits.fields", - evcode+".eventdata" + evcode+".eventdata", + evcode+".rescout", + evcode+".scoutnotice", + "todelete.colabarray", }; String[] files = FileEditor.getEventFiles(evcode); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java index 9b42c19..c5fbb07 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java @@ -4,12 +4,14 @@ import static com.ridgebotics.ridgescout.utility.FileEditor.baseDir; import android.util.Log; +import com.ridgebotics.ridgescout.types.ColabArray; import com.ridgebotics.ridgescout.utility.AlertManager; import com.ridgebotics.ridgescout.utility.FileEditor; import com.ridgebotics.ridgescout.utility.HttpGetFile; import com.ridgebotics.ridgescout.utility.HttpPutFile; import com.ridgebotics.ridgescout.utility.RequestTask; import com.ridgebotics.ridgescout.utility.SettingsManager; +import com.ridgebotics.ridgescout.utility.ToDelete; import org.json.JSONException; import org.json.JSONObject; @@ -96,6 +98,10 @@ public class HttpSync extends Thread { public void run() { isRunning = true; boolean sendMetaFiles = SettingsManager.getFTPSendMetaFiles(); + + ToDelete.reload_todelete_list(); + List removeFiles = ToDelete.todelete_list.get(); + String serverIP = SettingsManager.getFTPServer(); String serverKey = SettingsManager.getFTPKey(); @@ -113,6 +119,9 @@ public class HttpSync extends Thread { getLocalFileMetadata(); + localFiles.removeIf(localFile -> removeFiles.contains(localFile.filename+","+localFile.checksum)); + remoteFiles.removeIf(remoteFile -> removeFiles.contains(remoteFile.filename+","+remoteFile.checksum)); + @@ -187,7 +196,7 @@ public class HttpSync extends Thread { } - + ToDelete.deleteFiles(); setUpdateIndicator("Finished, " + upCount + " Up, " + downCount + " Down"); @@ -209,25 +218,6 @@ public class HttpSync extends Thread { return new Date(file.lastModified()); } - public static String getSHA256Hash(String filePath) throws IOException, NoSuchAlgorithmException { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - FileInputStream fis = new FileInputStream(filePath); - byte[] byteArray = new byte[1024]; - int bytesCount = 0; - - while ((bytesCount = fis.read(byteArray)) != -1) { - digest.update(byteArray, 0, bytesCount); - } - fis.close(); - - byte[] bytes = digest.digest(); - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(String.format("%02x", b)); - } - return sb.toString(); - } - private void getLocalFileMetadata() { File localDir = new File(baseDir); File[] localFileNames = localDir.listFiles(); @@ -244,9 +234,10 @@ public class HttpSync extends Thread { tf.filename = file.getName(); tf.updated = getLocalFileUtcTimestamp(file); try { - tf.checksum = getSHA256Hash(file.getPath()); + tf.checksum = FileEditor.getSHA256Hash(file.getName()); } catch (Exception e) { - + AlertManager.error("Failed to get hash of: " + file.getName(), e); + continue; } localFiles.add(tf); } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java index 9f0d65e..1575447 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/DataManager.java @@ -6,10 +6,6 @@ import com.ridgebotics.ridgescout.types.ColabArray; import com.ridgebotics.ridgescout.types.frcEvent; import com.ridgebotics.ridgescout.types.input.FieldType; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - // Static class to hold loaded data, for ease of access. public class DataManager { public static String evcode; @@ -63,6 +59,10 @@ public class DataManager { } } + + + + public static ColabArray rescout_list = new ColabArray(); public static void reload_rescout_list(){ String filename = evcode + ".rescout"; @@ -87,6 +87,11 @@ public class DataManager { } } + + + + + public static String scoutNotice = ""; public static void reload_scout_notice(){ diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/FileEditor.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/FileEditor.java index 9eff383..32dd346 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/FileEditor.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/FileEditor.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.nio.BufferOverflowException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -326,6 +328,29 @@ public final class FileEditor { + public static String getSHA256Hash(String filePath) throws IOException, NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + FileInputStream fis = new FileInputStream(baseDir + filePath); + byte[] byteArray = new byte[1024]; + int bytesCount = 0; + + while ((bytesCount = fis.read(byteArray)) != -1) { + digest.update(byteArray, 0, bytesCount); + } + fis.close(); + + byte[] bytes = digest.digest(); + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + + + + public static boolean setEvent(frcEvent event){ diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ToDelete.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ToDelete.java new file mode 100644 index 0000000..2822677 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ToDelete.java @@ -0,0 +1,151 @@ +package com.ridgebotics.ridgescout.utility; + +import static android.widget.LinearLayout.VERTICAL; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.widget.CheckBox; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import com.ridgebotics.ridgescout.types.ColabArray; + +import java.util.ArrayList; +import java.util.List; + +public class ToDelete { + public static final String filename = "todelete.colabarray"; + + public static void findCorruptedFiles(Context c) { + new Thread(() -> { + AlertManager.startLoading("Loading files..."); + List filenames = FileEditor.findCorruptedFiles(); + AlertManager.stopLoading(); + ((Activity) c).runOnUiThread(() -> { + deleteFiles(c, filenames, true); + }); + }).start(); + } + + public static void deleteFiles(Context c, List files, boolean defaultOption) { + ScrollView sv = new ScrollView(c); + LinearLayout ll = new LinearLayout(c); + ll.setOrientation(VERTICAL); + sv.addView(ll); + + CheckBox[] checkboxes = new CheckBox[files.size()]; + + for(int i =0; i < files.size(); i++){ + CheckBox cb = new CheckBox(c); + cb.setText(files.get(i)); + cb.setChecked(defaultOption); + ll.addView(cb); + checkboxes[i] = cb; + } + + + AlertDialog.Builder alert = new AlertDialog.Builder(c); + alert.setTitle("Delete files"); + alert.setView(sv); + alert.setNeutralButton("Cancel", null); + alert.setPositiveButton("Delete", (_dialogInterface, _i) -> { + List delete_files = new ArrayList<>(); + for(int i = 0; i < files.size(); i++) { + if(checkboxes[i].isChecked()) + delete_files.add(files.get(i)); + } + + + AlertDialog.Builder confirm = new AlertDialog.Builder(c); + alert.setTitle("Confirm"); + TextView tv = new TextView(c); + tv.setText("Are you sure you want to delete " + delete_files.size() + " files?"); + alert.setView(tv); + alert.setNeutralButton("Cancel", null); + alert.setPositiveButton("Delete", (dialogInterface, i) -> { + deleteFiles(delete_files); + }); + alert.setCancelable(false); + alert.create().show(); + }); + alert.setCancelable(false); + alert.create().show(); + } + + public static ColabArray todelete_list = new ColabArray(); + public static void reload_todelete_list(){ + if(!FileEditor.fileExist(ToDelete.filename)) {todelete_list = new ColabArray(); return;} + byte[] file = FileEditor.readFile(ToDelete.filename); + if(file == null) {todelete_list = new ColabArray(); return;} + + try { + todelete_list = ColabArray.decode(file); + } catch (Exception e){ + AlertManager.error("Error loading todelete list", e); + todelete_list = new ColabArray(); + } + } + + public static void save_todelete_list() { + try { + FileEditor.writeFile(ToDelete.filename, todelete_list.encode()); + } catch (Exception e){ + AlertManager.error("Error saving todelete list", e); + } + } + + private static void deleteFiles(List toDelete) { + reload_todelete_list(); + + for(String file : toDelete) { + + String hash; + try { + hash = FileEditor.getSHA256Hash(file); + } catch (Exception e) { + AlertManager.error("Failed to get hash of file: " + file, e); + continue; + } + + todelete_list.add(file+","+hash); + + FileEditor.deleteFile(file); + } + + save_todelete_list(); + } + + public static void deleteFiles() { + reload_todelete_list(); + List toDelete = todelete_list.get(); + for(String filename : FileEditor.getFiles()){ + try { + String hash = FileEditor.getSHA256Hash(filename); + + if(toDelete.contains(filename+","+hash)) { + FileEditor.deleteFile(filename); + } + + } catch (Exception e) { + AlertManager.error("Failed to get hash of file: " + filename, e); + continue; + } + } + } + + public static boolean contains(String localfile) { + try { + String hash = FileEditor.getSHA256Hash(localfile); + return contains(localfile, hash); + } catch (Exception e) { + AlertManager.error("Failed to get hash of file: " + localfile, e); + return false; + } + } + + public static boolean contains(String filename, String hash){ + return todelete_list.contains(filename+","+hash); + } +}