Add ByteBuilder, start work on parsing stored data

This commit is contained in:
Astatin3
2024-05-03 21:10:08 -06:00
parent bf64f8f6d1
commit 1321aad34c
33 changed files with 769 additions and 411 deletions
@@ -0,0 +1,94 @@
package com.astatin3.scoutingapp2025;
import android.util.Log;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
public class BuiltByteParser {
public static final Integer intType = 0;
public static final Integer stringType = 1;
public class byteParsingExeption extends Exception {
public byteParsingExeption() {}
public byteParsingExeption(String message) {
super(message);
}
}
public abstract class parsedObject {
public abstract Integer getType();
public abstract Object get();
}
public class intObject extends parsedObject{
int num;
public Integer getType(){return intType;}
public Object get(){return num;}
}
public class stringObject extends parsedObject{
String str;
public Integer getType(){return stringType;}
public Object get(){return str;}
}
public class rawObject extends parsedObject {
private int type;
public rawObject(int type){this.type = type;}
byte[] bytes;
public Integer getType(){return type;}
public Object get(){return bytes;}
}
byte[] bytes;
ArrayList<parsedObject> objects = new ArrayList<>();
public BuiltByteParser(byte[] bytes){
this.bytes = bytes;
}
public ArrayList<parsedObject> parse() throws byteParsingExeption {
if(bytes.length < 3){throw new byteParsingExeption("Invalid length");}
int curIndex = 0;
while(true){
// Log.i("t", String.valueOf(curIndex));
final int length = fileEditor.fromBytes(fileEditor.getByteBlock(bytes, curIndex, curIndex+2), 2);
final int type = bytes[curIndex+2] & 0xFF;
if(length == 0){
curIndex += 3;
continue;
}
final byte[] block;
try {
block = fileEditor.getByteBlock(bytes, curIndex + 3, curIndex + length + 3);
} catch(Exception e){
throw new byteParsingExeption("Array out of bounds");
}
switch(type){
case 0:
intObject io = new intObject();
io.num = fileEditor.fromBytes(block, length);
objects.add(io);
break;
case 1:
stringObject so = new stringObject();
so.str = new String(block, StandardCharsets.UTF_8);
objects.add(so);
break;
default:
rawObject ro = new rawObject(type);
ro.bytes = block;
objects.add(ro);
break;
}
curIndex += length + 3;
if(curIndex == bytes.length){
break;
}else if(curIndex > bytes.length){
throw new byteParsingExeption("Block length problem");
}
}
return objects;
}
}
@@ -0,0 +1,139 @@
package com.astatin3.scoutingapp2025;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
public class ByteBuilder {
ArrayList<byteType> bytesToBuild = new ArrayList<>();
public class buildingException extends Exception {
public buildingException() {}
public buildingException(String message) {
super(message);
}
}
private abstract static class byteType {
public abstract byte getType();
public abstract int length();
public abstract byte[] build();
}
private class intType extends byteType {
public int precision;
public int num;
public byte getType(){return 0;}
public int length(){return precision;}
public byte[] build(){
return fileEditor.toBytes(num, precision);
}
}
private int getLeastBytePrecision(int num){
if(num <= 1){return 1;}
return (int) Math.ceil(Math.log(Math.abs(num))/Math.log(8));
}
public ByteBuilder addInt(int num) throws buildingException {
// Get closest number of bytes
int precision = getLeastBytePrecision(num);
return addInt(num, precision);
}
public ByteBuilder addInt(int num, int precision) throws buildingException {
if(precision <= 0){throw new buildingException("Invalid precision: " + precision);}
if(precision > 65536){throw new buildingException("Precision too large (greter than 65536)");}
if(precision < getLeastBytePrecision(num)){throw new buildingException("Precision too small");}
if(num > Integer.MAX_VALUE){throw new buildingException("Integer overflow");}
if(num < Integer.MIN_VALUE){throw new buildingException("Integer overflow");}
intType intType = new intType();
intType.num = num;
intType.precision = precision;
bytesToBuild.add(intType);
return this;
}
private class stringType extends byteType {
public byte[] bytes;
public byte getType(){return 1;}
public int length(){return bytes.length;}
public byte[] build(){
return bytes;
// return str.getBytes(charset);
}
}
public ByteBuilder addString(String str) throws buildingException {
if(str.length() > 65536){throw new buildingException("String too long (greater than 65536)");}
stringType stringType = new stringType();
// To get the length correctly, the string bytes need to be precalculated
stringType.bytes = str.getBytes(StandardCharsets.UTF_8);
bytesToBuild.add(stringType);
return this;
}
private class rawType extends byteType {
public int type;
public byte[] bytes;
public byte getType(){return (byte) type;}
public int length(){return bytes.length;}
public byte[] build(){
return bytes;
}
}
public ByteBuilder addRaw(int type, byte[] bytes) throws buildingException {
if(bytes.length > 65536){throw new buildingException("Byte array length to long (greater than 65536)");}
rawType rawType = new rawType();
rawType.type = type;
rawType.bytes = bytes;
bytesToBuild.add(rawType);
return this;
}
public byte[] build() throws buildingException {
if(bytesToBuild.size() == 0){throw new buildingException("Cannot build null data");}
int length = bytesToBuild.size() * 3;
for(byteType bt : bytesToBuild){
length += bt.length();
}
byte[] bytes = new byte[length];
int bytesFilled = 0;
for(byteType bt : bytesToBuild){
byte[] blockLength = fileEditor.toBytes(bt.length(), 2);
bytes[bytesFilled] = blockLength[0];
bytesFilled += 1;
bytes[bytesFilled] = blockLength[1];
bytesFilled += 1;
bytes[bytesFilled] = bt.getType();
bytesFilled += 1;
// if(bt.length == 0)
// continue;
int i = 1;
byte[] newBytes = bt.build();
for(byte b : newBytes){
// Log.i("i", (bytesFilled+1) + "/" + length + " (" + i + "/" + bt.length() + ")");
bytes[bytesFilled] = b;
bytesFilled += 1;
i++;
}
}
return bytes;
}
}
@@ -28,7 +28,7 @@ public class MainActivity extends AppCompatActivity {
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_notifications, R.id.navigation_tba)
R.id.navigation_scouting, R.id.navigation_transfer, R.id.navigation_settings)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
@@ -1,13 +1,6 @@
package com.astatin3.scoutingapp2025;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.View;
import java.io.BufferedReader;
import java.io.IOException;
@@ -43,8 +36,6 @@ public class RequestTask extends AsyncTask<String, String, String> {
else {
return null; // See documentation for more info on response handling
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
@@ -52,10 +43,10 @@ public class RequestTask extends AsyncTask<String, String, String> {
}
private static String readStream(InputStream in) {
BufferedReader reader = null;
StringBuffer response = new StringBuffer();
StringBuilder response = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
@@ -1,10 +0,0 @@
package com.astatin3.scoutingapp2025.Utils;
import java.util.ArrayList;
public class frcEvent {
public String eventCode;
public String name;
public ArrayList<frcMatch> matches;
public ArrayList<frcTeam> teams;
}
@@ -1,8 +0,0 @@
package com.astatin3.scoutingapp2025.Utils;
public class frcMatch {
public frcMatch(){}
public int matchIndex = 0;
public int[] blueAlliance;
public int[] redAlliance;
}
@@ -1,22 +0,0 @@
package com.astatin3.scoutingapp2025.Utils;
public class frcTeam {
public int teamNumber = 0;
public String teamName = null;
public String city = null;
public String stateOrProv = null;
public String school = null;
public String country = null;
public int startingYear = 0;
public String getDescription(){
return teamName + " Started in " + startingYear + ", and is from " + school + " in " + city + ", " + stateOrProv + ", " + country;
}
public frcTeam encode(){
return this;
}
public frcTeam decode(){
return this;
}
}
@@ -1,11 +1,17 @@
package com.astatin3.scoutingapp2025;
import android.content.Context;
import android.util.Log;
import com.astatin3.scoutingapp2025.Utils.frcMatch;
import com.astatin3.scoutingapp2025.Utils.frcTeam;
import com.astatin3.scoutingapp2025.types.frcEvent;
import com.astatin3.scoutingapp2025.types.frcMatch;
import com.astatin3.scoutingapp2025.types.frcTeam;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.BufferOverflowException;
@@ -17,7 +23,7 @@ import java.util.zip.Deflater;
import java.util.zip.Inflater;
public final class fileEditor {
// private final static String baseDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
private final static String baseDir = "/data/data/com.astatin3.scoutingapp2025/files/";
public static final byte internalDataVersion = 0x01;
public static final int maxCompressedBlockSize = 4096;
@@ -25,11 +31,11 @@ public final class fileEditor {
public static String binaryVisualize(byte[] bytes){
String returnStr = "";
for(int a=0;a<bytes.length;a++){
for(int b=0;b<8;b++){
returnStr += String.valueOf((bytes[a] >> b) & 1);
for (byte aByte : bytes) {
for (int b = 7; b >= 0; b--) {
returnStr += String.valueOf((aByte >> b) & 1);
}
returnStr += " (" + (int)bytes[a] + ")\n";
returnStr += " (" + (int) aByte + ")\n";
}
return returnStr;
}
@@ -43,7 +49,7 @@ public final class fileEditor {
public static byte[] toBytes(int num, int byteCount){
if(num < 0 || num > (Math.pow(2,byteCount*8)-1)){
if(num > (Math.pow(2,byteCount*8)-1)){
throw new BufferOverflowException();
}
byte[] bytes = new byte[byteCount];
@@ -118,11 +124,11 @@ public final class fileEditor {
return outputStream.toByteArray();
}
private static boolean writeToFile(Context context, String filepath, String data) {
private static boolean writeToFile(String filepath, byte[] data) {
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(filepath, Context.MODE_PRIVATE));
outputStreamWriter.write(data);
outputStreamWriter.close();
FileOutputStream output = new FileOutputStream(filepath);
output.write(data);
output.close();
return true;
}
catch (IOException e) {
@@ -131,6 +137,24 @@ public final class fileEditor {
}
}
public static byte[] readFile(String path){
File file = new File(path);
int size = (int) file.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
return bytes;
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static String intSplit(int[] intArr, String splitStr){
String returnStr = "";
for(int i=0;i<intArr.length;i++){
@@ -142,24 +166,32 @@ public final class fileEditor {
return returnStr;
}
public static boolean setMatches(Context context, String key, String matchName, ArrayList<frcMatch> matches){
final String filename = (key + "-matches.csv");
String csvData = "";
csvData += key + "\n";
csvData += matchName + "\n";
for(int i=0;i<matches.size();i++){
final frcMatch match = matches.get(i);
csvData += String.valueOf(match.matchIndex)
+ "," + intSplit(match.redAlliance, ",")
+ "," + intSplit(match.blueAlliance, ",") + "\n";
}
return writeToFile(context, filename, csvData);
public static boolean setEvent(frcEvent event){
final String filename = (baseDir + event.eventCode + ".eventdata");
return writeToFile(filename, event.encode());
}
public static ArrayList<String> getEventList(){
File f = new File(baseDir);
File[] files = f.listFiles();
ArrayList<String> outFiles = new ArrayList<>();
if(files == null){return outFiles;}
for (File file : files) {
if(!file.isDirectory() && file.getName().endsWith(".eventdata")) {
outFiles.add(file.getName());
}
}
return outFiles;
}
public static boolean setTeams(Context context, String key, ArrayList<frcTeam> teams){
return true;
}
@@ -0,0 +1,5 @@
package com.astatin3.scoutingapp2025.types;
public class file {
public static final int typecode = 255;
}
@@ -0,0 +1,71 @@
package com.astatin3.scoutingapp2025.types;
import android.util.Log;
import androidx.annotation.NonNull;
import com.astatin3.scoutingapp2025.BuiltByteParser;
import com.astatin3.scoutingapp2025.ByteBuilder;
import java.util.ArrayList;
public class frcEvent {
public static final int typecode = 254;
public String eventCode;
public String name;
public ArrayList<frcMatch> matches;
public ArrayList<frcTeam> teams;
public byte[] encode(){
try {
ByteBuilder bb = new ByteBuilder()
.addString(eventCode)
.addString(name);
for(frcTeam teams : teams){
bb.addRaw(frcTeam.typecode, teams.encode());
}
for(frcMatch match : matches){
bb.addRaw(frcMatch.typecode, match.encode());
}
return bb.build();
} catch (ByteBuilder.buildingException e) {
e.printStackTrace();
return null;
}
}
public static frcEvent decode(byte[] bytes){
try{
ArrayList<BuiltByteParser.parsedObject> objects = new BuiltByteParser(bytes).parse();
frcEvent frc = new frcEvent();
frc.eventCode = (String) objects.get(0).get();
frc.name = (String) objects.get(1).get();
frc.matches = new ArrayList<>();
frc.teams = new ArrayList<>();
for(BuiltByteParser.parsedObject object : objects){
if(object.getType() == frcTeam.typecode){
frc.teams.add(frcTeam.decode((byte[]) object.get()));
}else if(object.getType() == frcMatch.typecode){
frc.matches.add(frcMatch.decode((byte[]) object.get()));
}
}
return frc;
}catch (BuiltByteParser.byteParsingExeption e){
e.printStackTrace();
return null;
}
}
@NonNull
public String toString(){
return "Name: " + name + ", Code: " + eventCode + " numTeams: " + teams.size() + " numMatches: " + matches.size();
}
}
@@ -0,0 +1,55 @@
package com.astatin3.scoutingapp2025.types;
import com.astatin3.scoutingapp2025.BuiltByteParser;
import com.astatin3.scoutingapp2025.ByteBuilder;
import java.util.ArrayList;
public class frcMatch {
public static final int typecode = 253;
public frcMatch(){}
public int matchIndex = 0;
public int[] blueAlliance = new int[3];
public int[] redAlliance = new int[3];
public byte[] encode(){
try {
return new ByteBuilder()
.addInt(matchIndex)
.addInt(blueAlliance[0])
.addInt(blueAlliance[1])
.addInt(blueAlliance[2])
.addInt(redAlliance[0])
.addInt(redAlliance[1])
.addInt(redAlliance[2])
.build();
} catch (ByteBuilder.buildingException e) {
e.printStackTrace();
return new byte[1];
}
}
public static frcMatch decode(byte[] bytes){
try {
ArrayList<BuiltByteParser.parsedObject> objects = new BuiltByteParser(bytes).parse();
frcMatch frc = new frcMatch();
frc.matchIndex = (int) objects.get(0).get();
frc.blueAlliance[0] = (int) objects.get(1).get();
frc.blueAlliance[1] = (int) objects.get(2).get();
frc.blueAlliance[2] = (int) objects.get(3).get();
frc.redAlliance[0] = (int) objects.get(4).get();
frc.redAlliance[1] = (int) objects.get(5).get();
frc.redAlliance[2] = (int) objects.get(6).get();
return frc;
} catch (BuiltByteParser.byteParsingExeption e) {
e.printStackTrace();
return null;
}
}
}
@@ -0,0 +1,59 @@
package com.astatin3.scoutingapp2025.types;
import com.astatin3.scoutingapp2025.BuiltByteParser;
import com.astatin3.scoutingapp2025.ByteBuilder;
import java.util.ArrayList;
public class frcTeam {
public static final int typecode = 252;
public int teamNumber = 0;
public String teamName = "null";
public String city = "null";
public String stateOrProv = "null";
public String school = "null";
public String country = "null";
public int startingYear = 0;
public String getDescription(){
return teamName + " Started in " + startingYear + ", and is from " + school + " in " + city + ", " + stateOrProv + ", " + country;
}
public byte[] encode(){
try {
return new ByteBuilder()
.addInt(teamNumber)
.addString(teamName)
.addString(city)
.addString(stateOrProv)
.addString(school)
.addString(country)
.addInt(startingYear)
.build();
} catch (ByteBuilder.buildingException e) {
e.printStackTrace();
return null;
}
}
public static frcTeam decode(byte[] bytes){
try {
ArrayList<BuiltByteParser.parsedObject> objects = new BuiltByteParser(bytes).parse();
frcTeam frc = new frcTeam();
frc.teamNumber = (int) objects.get(0).get();
frc.teamName = (String) objects.get(1).get();
frc.city = (String) objects.get(2).get();
frc.stateOrProv = (String) objects.get(3).get();
frc.school = (String) objects.get(4).get();
frc.country = (String) objects.get(5).get();
frc.startingYear = (int) objects.get(6).get();
return frc;
} catch (BuiltByteParser.byteParsingExeption e) {
e.printStackTrace();
return null;
}
}
}
@@ -13,7 +13,7 @@ public class JSONUtil {
for (int i=0; i<array.length(); i++){
asList.add(array.opt(i));
}
Collections.sort(asList, c);
asList.sort(c);
JSONArray res = new JSONArray();
for (Object o : asList){
res.put(o);
@@ -1,37 +1,19 @@
package com.astatin3.scoutingapp2025.ui.TBA;
package com.astatin3.scoutingapp2025.ui.Settings;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TableRow;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.RequestTask;
import com.astatin3.scoutingapp2025.databinding.FragmentTbaBinding;
import com.astatin3.scoutingapp2025.ui.JSONUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Comparator;
import java.util.function.Function;
import com.astatin3.scoutingapp2025.databinding.FragmentSettingsBinding;
public class TBAFragment extends Fragment {
// private final String
private final String TBAAddress = "https://www.thebluealliance.com/api/v3/";
private final String TBAHeader = "X-TBA-Auth-Key: tjEKSZojAU2pgbs2mBt06SKyOakVhLutj3NwuxLTxPKQPLih11aCIwRIVFXKzY4e";
private FragmentTbaBinding binding;
public class Settings extends Fragment {
private FragmentSettingsBinding binding;
private android.widget.ScrollView ScrollArea;
private android.widget.TableLayout Table;
@@ -48,7 +30,7 @@ public class TBAFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentTbaBinding.inflate(inflater, container, false);
binding = FragmentSettingsBinding.inflate(inflater, container, false);
View root = binding.getRoot();
return root;
@@ -0,0 +1,35 @@
package com.astatin3.scoutingapp2025.ui.scouting;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.databinding.FragmentDataBinding;
import com.astatin3.scoutingapp2025.fileEditor;
public class dataFragment extends Fragment {
private FragmentDataBinding binding;
private void setDropdownItems(Spinner dropdown, String[] items){
ArrayAdapter<String> adapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_spinner_item, items);
dropdown.setAdapter(adapter);
}
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentDataBinding.inflate(inflater, container, false);
View root = binding.getRoot();
return root;
}
}
@@ -1,26 +0,0 @@
package com.astatin3.scoutingapp2025.ui.home;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.databinding.FragmentHomeBinding;
public class HomeFragment extends Fragment {
private FragmentHomeBinding binding;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentHomeBinding.inflate(inflater, container, false);
View root = binding.getRoot();
return root;
}
}
@@ -0,0 +1,40 @@
z1package com.astatin3.scoutingapp2025.ui.scouting;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.astatin3.scoutingapp2025.databinding.FragmentScoutingBinding;
import com.astatin3.scoutingapp2025.fileEditor;
public class scoutingFragment extends Fragment {
private FragmentScoutingBinding binding;
private void setDropdownItems(Spinner dropdown, String[] items){
ArrayAdapter<String> adapter = new ArrayAdapter<>(requireActivity(), android.R.layout.simple_spinner_item, items);
dropdown.setAdapter(adapter);
}
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentScoutingBinding.inflate(inflater, container, false);
View root = binding.getRoot();
Spinner dropdown = binding.eventDropdown;
setDropdownItems(dropdown, fileEditor.getEventList().toArray(new String[0]));
return root;
}
}
@@ -13,8 +13,9 @@ import android.widget.TableRow;
import android.widget.TextView;
import com.astatin3.scoutingapp2025.RequestTask;
import com.astatin3.scoutingapp2025.Utils.frcMatch;
import com.astatin3.scoutingapp2025.Utils.frcTeam;
import com.astatin3.scoutingapp2025.types.frcEvent;
import com.astatin3.scoutingapp2025.types.frcMatch;
import com.astatin3.scoutingapp2025.types.frcTeam;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.ui.JSONUtil;
@@ -29,7 +30,7 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.function.Function;
import java.util.Objects;
public class TBAView extends ScrollView {
private final String TBAAddress = "https://www.thebluealliance.com/api/v3/";
@@ -66,12 +67,9 @@ public class TBAView extends ScrollView {
Table.addView(tr);
final RequestTask rq = new RequestTask();
rq.onResult(new Function<String, String>() {
@Override
public String apply(String s) {
eventTable(s);
return null;
}
rq.onResult(s -> {
eventTable(s);
return null;
});
rq.execute(TBAAddress + "events/"+yearStr, TBAHeader);
@@ -100,13 +98,6 @@ public class TBAView extends ScrollView {
boolean toggle = false;
// TableRow tr = new TableRow(getContext());
// addTableText(tr, "Key");
// addTableText(tr, "Title");
// addTableText(tr, "Type");
//
// Table.addView(tr);
for(int i=0;i<data.length();i++){
TableRow tr = new TableRow(getContext());
TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams(
@@ -156,39 +147,30 @@ public class TBAView extends ScrollView {
}
tr.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
Table.removeAllViews();
Table.setStretchAllColumns(true);
Table.bringToFront();
tr.setOnClickListener(v -> {
Table.removeAllViews();
Table.setStretchAllColumns(true);
Table.bringToFront();
TableRow tr = new TableRow(getContext());
addTableText(tr, "Downloading Teams...");
Table.addView(tr);
TableRow tr1 = new TableRow(getContext());
addTableText(tr1, "Downloading Teams...");
Table.addView(tr1);
final RequestTask rq = new RequestTask();
rq.onResult(new Function<String, String>() {
@Override
public String apply(String teamsStr) {
TableRow tr = new TableRow(getContext());
addTableText(tr, "Downloading Matches...");
Table.addView(tr);
final RequestTask rq = new RequestTask();
rq.onResult(teamsStr -> {
TableRow tr11 = new TableRow(getContext());
addTableText(tr11, "Downloading Matches...");
Table.addView(tr11);
final RequestTask rq = new RequestTask();
rq.onResult(new Function<String, String>() {
@Override
public String apply(String matchesStr) {
matchTable(matchesStr, teamsStr, j);
return null;
}
});
rq.execute((TBAAddress + "event/" + matchKey + "/matches"), TBAHeader);
return null;
}
final RequestTask rq1 = new RequestTask();
rq1.onResult(matchesStr -> {
matchTable(matchesStr, teamsStr, j);
return null;
});
rq.execute((TBAAddress + "event/" + matchKey + "/teams"), TBAHeader);
}
rq1.execute((TBAAddress + "event/" + matchKey + "/matches"), TBAHeader);
return null;
});
rq.execute((TBAAddress + "event/" + matchKey + "/teams"), TBAHeader);
});
// tr.addView(cl);
@@ -201,7 +183,7 @@ public class TBAView extends ScrollView {
}
}
class matchComparator implements Comparator<JSONObject>
static class matchComparator implements Comparator<JSONObject>
{
public int compare(JSONObject a, JSONObject b)
@@ -286,20 +268,18 @@ public class TBAView extends ScrollView {
Table.addView(tr);
final JSONArray sortedMatchData = JSONUtil.sort(matchData, new Comparator(){
public int compare(Object a, Object b){
JSONObject ja = (JSONObject)a;
JSONObject jb = (JSONObject)b;
try {
return ja.getInt("match_number") - jb.getInt("match_number");
}catch (JSONException j){
return 0;
}
final JSONArray sortedMatchData = JSONUtil.sort(matchData, (a, b) -> {
JSONObject ja = (JSONObject)a;
JSONObject jb = (JSONObject)b;
try {
return ja.getInt("match_number") - jb.getInt("match_number");
}catch (JSONException j){
return 0;
}
});
final ArrayList<frcMatch> matchesOBJ = new ArrayList<frcMatch>();
final ArrayList<frcMatch> matchesOBJ = new ArrayList<>();
boolean toggle = false;
int matchCount = 1;
@@ -334,12 +314,12 @@ public class TBAView extends ScrollView {
if(b < 3){
String str = redAlliance.getString(b).substring(3);
redKeys[b] = (int)Integer.parseInt(str);
redKeys[b] = Integer.parseInt(str);
text.setText(str);
text.setBackgroundColor(0x50ff0000);
}else{
String str = blueAlliance.getString(b-3).substring(3);
blueKeys[b-3] = (int)Integer.parseInt(str);
blueKeys[b-3] = Integer.parseInt(str);
text.setText(str);
text.setBackgroundColor(0x500000ff);
}
@@ -357,14 +337,11 @@ public class TBAView extends ScrollView {
toggle = !toggle;
}
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(saveData(matchesOBJ, teamData, eventData)){
alert("Info", "Saved!");
}else{
alert("Error", "Error saving files.");
}
btn.setOnClickListener(v -> {
if(saveData(matchesOBJ, teamData, eventData)){
alert("Info", "Saved!");
}else{
alert("Error", "Error saving files.");
}
});
@@ -385,7 +362,7 @@ public class TBAView extends ScrollView {
}
ArrayList<frcTeam> teams = new ArrayList<frcTeam>();
ArrayList<frcTeam> teams = new ArrayList<>();
for(int i=0;i<teamData.length();i++){
frcTeam teamObj = new frcTeam();
JSONObject team = teamData.getJSONObject(i);
@@ -401,8 +378,13 @@ public class TBAView extends ScrollView {
teams.add(teamObj);
}
return fileEditor.setMatches(getContext(), matchKey, matchName, matchData) &&
fileEditor.setTeams(getContext(), matchKey, teams);
frcEvent event = new frcEvent();
event.name = matchName;
event.eventCode = matchKey;
event.teams = teams;
event.matches = matchData;
return fileEditor.setEvent(event);
}catch (JSONException j){
j.printStackTrace();
alert("Error", "Invalid JSON");
File diff suppressed because one or more lines are too long
@@ -1,12 +1,10 @@
package com.astatin3.scoutingapp2025.ui.transfer;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -15,13 +13,11 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.nio.charset.StandardCharsets;
@@ -47,8 +43,6 @@ public class generatorView extends ConstraintLayout {
private final int maxQrSize = 500;
private int qrSize = 200;
private int curCodeIndex = 0;
private final int defaultQrDelay = 419;
private int qrDelay = 0;
private int qrIndex = 0;
@@ -74,7 +68,7 @@ public class generatorView extends ConstraintLayout {
return null;
}
Map<EncodeHintType, Object> hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
// The Charset must be UTF-8, Or data will not be transferred properly. IDK why.
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
@@ -117,10 +111,6 @@ public class generatorView extends ConstraintLayout {
qrIndexN = binding.qrIndexN;
qrIndexD = binding.qrIndexD;
// byte[] randomData = new byte[4596];
// new Random().nextBytes(randomData);
// inputData = randomData;
String compiledData = "";
@@ -148,21 +138,9 @@ public class generatorView extends ConstraintLayout {
}
// byte[] tempData = fileEditor.compress(inputData);
// String compiledData = new String(tempData, StandardCharsets.ISO_8859_1);
sendData(compiledData);
}
private void alert(String title, String content) {
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
alert.setMessage(content);
alert.setTitle(title);
alert.setPositiveButton("OK", null);
alert.setCancelable(true);
alert.create().show();
}
private void sendData(String data){
// minQrSize = 0;
@@ -196,7 +174,7 @@ public class generatorView extends ConstraintLayout {
public void onStopTrackingTouch(SeekBar seekBar) {
qrSize = seekBar.getProgress() + minQrSize;
// qrCount = (int)Math.ceil((double) (data.length()+1)/qrSize);
qrCount = (int)((data.length()+1)/qrSize)+1;
qrCount = ((data.length()+1)/qrSize) +1;
qrIndexD.setText(String.valueOf(qrCount));
sendData(data);
}
@@ -204,7 +182,7 @@ public class generatorView extends ConstraintLayout {
qrSpeedSlider.setProgress(defaultQrDelay+5);
qrBitmaps = new ArrayList<Bitmap>();
qrBitmaps = new ArrayList<>();
int randID = new Random().nextInt(255);
@@ -217,10 +195,10 @@ public class generatorView extends ConstraintLayout {
try {
// alert("test", ""+Math.ceil((double)data.length()/(double)qrSize));
qrBitmaps.add(generateQrCode(
String.valueOf(fileEditor.byteToChar(fileEditor.internalDataVersion)) +
fileEditor.byteToChar(fileEditor.internalDataVersion) +
String.valueOf(fileEditor.byteToChar(randID)) +
String.valueOf(fileEditor.byteToChar(i)) +
String.valueOf(fileEditor.byteToChar(qrCount-1)) +
fileEditor.byteToChar(i) +
fileEditor.byteToChar(qrCount - 1) +
data.substring(start, end)
));
// alert("title", ""+(qrCount-1));
@@ -11,6 +11,8 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
public class qrOverlayView extends View {
PointF[] points;
@@ -50,7 +52,7 @@ public class qrOverlayView extends View {
}
@Override
public void draw(Canvas canvas) {
public void draw(@NonNull Canvas canvas) {
super.draw(canvas);
if (points != null) {
for (PointF pointF : points) {
@@ -58,11 +60,10 @@ public class qrOverlayView extends View {
}
}
if(barColors != null){
final int width = (int)(getWidth()/barColors.length);
final int width = getWidth()/barColors.length;
final int top = 0;
final int bottom = barHeight;
final int margin = 5*(int)((double)width/getWidth());
for(int i=0;i<barColors.length;i++){
@@ -7,7 +7,6 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.media.Image;
import android.os.Handler;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
@@ -29,9 +28,7 @@ import androidx.lifecycle.LifecycleOwner;
import com.astatin3.scoutingapp2025.databinding.FragmentTransferBinding;
import com.astatin3.scoutingapp2025.fileEditor;
import com.astatin3.scoutingapp2025.qrScanTask;
import com.dlazaro66.qrcodereaderview.QRCodeReaderView;
import com.google.common.util.concurrent.ListenableFuture;
import java.nio.ByteBuffer;
@@ -40,38 +37,12 @@ import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.zip.DataFormatException;
//public class scannerView extends androidx.appcompat.widget.AppCompatImageView {
public class scannerView extends ConstraintLayout {
// public static class fixedQRCodeReaderView extends QRCodeReaderView {
// public fixedQRCodeReaderView(Context context) {
// super(context, null);
// }
// }
private QRCodeReaderView qrCodeReaderView;
private qrOverlayView qrOverlayView;
private Handler uiHandler;
private ScriptIntrinsicYuvToRGB script;
// private class codeReadListener implements QRCodeReaderView.OnQRCodeReadListener {
// @Override
// public void onQRCodeRead(String text, PointF[] points) {
// qrOverlayView.setPoints(points);
//
//// alert("Info", ""+(fileEditor.byteFromChar(text.charAt(3))+1));
//
// compileData(
// fileEditor.byteFromChar(text.charAt(0)),
// fileEditor.byteFromChar(text.charAt(1)),
// fileEditor.byteFromChar(text.charAt(2)),
// (fileEditor.byteFromChar(text.charAt(3))+1),
// text.substring(4)
// );
// }
// }
private void alert(String title, String content) {
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
@@ -99,8 +70,6 @@ public class scannerView extends ConstraintLayout {
scale = ((float) getWidth() / bmp.getWidth()) * ((float) 16 / 9);
binding.scannerImage.setTranslationX(0);
binding.scannerImage.setTranslationY(0);
// binding.scannerImage.setScaleX(scale);
// binding.scannerImage.setScaleY(scale);
}
scanQRCode(bmp);
binding.scannerImage.setImageBitmap(bmp);
@@ -130,16 +99,8 @@ public class scannerView extends ConstraintLayout {
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// int L = levelMap[clamp((yBuffer.get() & 0xff) - thresholdOffset, 0, 255)];
// int L = clamp(levelMap[yBuffer.get() & 0xff]-thresholdOffset, 0, 255);
int L = levelMap[yBuffer.get() & 0xff];
pixels[y * width + x] = 0xff000000 | (L << 16) | (L << 8) | L;
// if(L > threshold) {
// pixels[y * width + x] = 0xffffffff;
// }else{
// pixels[y * width + x] = 0xff000000;
// }
// pixels[y * width + x] = levelMap[L];
}
}
@@ -152,21 +113,18 @@ public class scannerView extends ConstraintLayout {
qrScanTask async = new qrScanTask();
async.setImage(bitmap);
async.onResult(new Function<String, String>() {
@Override
public String apply(String data) {
if(data != null){
async.onResult(data -> {
if(data != null){
// alert("test", ""+fileEditor.byteFromChar(data.charAt(0)));
compileData(
fileEditor.byteFromChar(data.charAt(0)),
fileEditor.byteFromChar(data.charAt(1)),
fileEditor.byteFromChar(data.charAt(2)),
(fileEditor.byteFromChar(data.charAt(3))+1),
data.substring(4)
);
}
return null;
compileData(
fileEditor.byteFromChar(data.charAt(0)),
fileEditor.byteFromChar(data.charAt(1)),
fileEditor.byteFromChar(data.charAt(2)),
(fileEditor.byteFromChar(data.charAt(3))+1),
data.substring(4)
);
}
return null;
});
async.execute();
@@ -242,16 +200,13 @@ public class scannerView extends ConstraintLayout {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture
= ProcessCameraProvider.getInstance(this.getContext());
cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
}, ContextCompat.getMainExecutor(this.getContext()));
}
@@ -282,25 +237,22 @@ public class scannerView extends ConstraintLayout {
@OptIn(markerClass = ExperimentalGetImage.class) @Override
public void analyze(@NonNull ImageProxy image) {
Image img = Objects.requireNonNull(image.getImage());
// Log.i("test", img.getWidth() + ", " + img.getHeight());
// final Bitmap bmp = yuvConvertor.toBitmap(img);
if(img != null) {
uiHandler.post(new Runnable() {
Bitmap bmp = toGreyscale(img);
@Override
public void run() {
uiHandler.post(new Runnable() {
final Bitmap bmp = toGreyscale(img);
@Override
public void run() {
// setImage(toGreyscale(bmp));
setImage(bmp);
}
});
}
setImage(bmp);
}
});
image.close();
}
});
cameraProvider.unbindAll();
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)lifecycle,
cameraProvider.bindToLifecycle(lifecycle,
cameraSelector, imageAnalysis, preview);
// preview.setSurfaceProvider(binding.previewView.getSurfaceProvider());
@@ -350,8 +302,6 @@ public class scannerView extends ConstraintLayout {
try {
byte[] compiledBytes = compiledString.getBytes(StandardCharsets.ISO_8859_1);
// alert(count+", "+compiledData.length()+", "+compiledBytes.length, ""+fileEditor.fromBytes(fileEditor.getByteBlock(compiledBytes, 0,2),2));
// alert("completed", new String(fileEditor.decompress(compiledBytes), StandardCharsets.ISO_8859_1));
alert("completed", blockUncompress(compiledBytes));
}catch (Exception e){
e.printStackTrace();