From f344663f7f3b7288691054979effef38cf5f3302 Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Mon, 6 Jul 2026 22:41:55 -0700 Subject: [PATCH 01/13] initial + gradle upgrade --- .idea/planningMode.xml | 13 + app/build.gradle.kts | 2 + app/src/main/AndroidManifest.xml | 1 + .../scouting_app/activities/SubmitData.java | 77 +++++ .../scouting_app/utility/CPR_Network.java | 134 ++++++++- .../team3663/scouting_app/utility/Logger.java | 5 +- gradle/libs.versions.toml | 22 +- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 7 +- gradlew | 283 +++++++++++------- gradlew.bat | 63 ++-- 11 files changed, 443 insertions(+), 164 deletions(-) create mode 100644 .idea/planningMode.xml diff --git a/.idea/planningMode.xml b/.idea/planningMode.xml new file mode 100644 index 00000000..f2ea403f --- /dev/null +++ b/.idea/planningMode.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ce1c148b..6e485b48 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,11 +48,13 @@ base { dependencies { implementation(libs.appcompat) + implementation(libs.documentfile) implementation(libs.material) implementation(libs.activity) implementation(libs.constraintlayout) implementation(libs.qr.generator) implementation(libs.preference) + implementation(libs.mssql.jdbc) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d5ce06dc..c2ef462d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 17a322bb..36357db9 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -16,6 +16,8 @@ import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Toast; + import androidx.activity.EdgeToEdge; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; @@ -77,6 +79,8 @@ protected void onCreate(Bundle in_savedInstanceState) { initMatch(); initQR(); initBluetooth(); + initGoogle(); + initDatabase(); initQuit(); initNext(); initOverride(); @@ -361,6 +365,18 @@ private void initAchievements() { // Output: void // ============================================================================================= private void initMatch() { + submitDataBinding.spinnerMatch.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView adapterView, View view, int i, long l) { + // Save off what you selected to be used until changed again + Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + } + + @Override + public void onNothingSelected(AdapterView adapterView) { + } + }); + // Adds the items from the match log files array to the list ArrayAdapter adp_Match = new ArrayAdapter<>(this, R.layout.cpr_spinner, FindMatches()); @@ -368,6 +384,7 @@ private void initMatch() { submitDataBinding.spinnerMatch.setAdapter(adp_Match); // Set the selection (if there are any) to the latest match (largest value in the list) if (adp_Match.getCount() > 0) submitDataBinding.spinnerMatch.setSelection(adp_Match.getCount() - 1, true); + Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); } // ============================================================================================= @@ -460,6 +477,66 @@ private void initBluetooth() { }); } + // ============================================================================================= + // Function: initGoogle + // Description: Initialize the Google field + // Parameters: void + // Output: void + // ============================================================================================= + private void initGoogle() { + if (!Globals.network.hasActiveInternet()) { + submitDataBinding.butSendGoogle.setEnabled(false); + return; + } + + submitDataBinding.butSendGoogle.setOnClickListener(view -> { + Toast.makeText(this, "Coming Soon...", Toast.LENGTH_SHORT).show(); + }); + } + + // ============================================================================================= + // Function: initDatabase + // Description: Initialize the Database field + // Parameters: void + // Output: void + // ============================================================================================= + private void initDatabase() { + if (!Globals.network.hasActiveInternet()) { + submitDataBinding.butSendDatabase.setEnabled(false); + return; + } + + submitDataBinding.butSendDatabase.setOnClickListener(view -> { + //Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + submitDataBinding.butSendDatabase.setEnabled(false); + + Globals.network.sendFileToSQLServer(result -> { + submitDataBinding.butSendDatabase.setEnabled(true); + switch (result) { + case TRANSMISSION_SUCCESS: + Toast.makeText(this, "Successfully transmitted!", Toast.LENGTH_SHORT).show(); + break; + case NO_NETWORK: + Toast.makeText(this, "No network connection", Toast.LENGTH_SHORT).show(); + break; + case HOST_UNREACHABLE: + Toast.makeText(this, "SQL Server is unreachable", Toast.LENGTH_SHORT).show(); + break; + case NO_DATA: + Toast.makeText(this, "No data to send", Toast.LENGTH_SHORT).show(); + break; + case SQL_EXCEPTION: + Toast.makeText(this, "SQL Server Exception", Toast.LENGTH_SHORT).show(); + break; + case TRANSMISSION_FAILURE: + default: + Toast.makeText(this, "Transmission failed", Toast.LENGTH_SHORT).show(); + break; + } + }); + }); + } + // ============================================================================================= // Function: initQuit // Description: Initialize the Quit button diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index e42c8f61..87a11690 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -10,10 +10,21 @@ import android.provider.Settings; import androidx.annotation.NonNull; +import androidx.documentfile.provider.DocumentFile; +import com.team3663.scouting_app.config.Constants; +import com.team3663.scouting_app.config.Globals; + +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.Socket; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -33,9 +44,13 @@ public class CPR_Network { // Why a reachability check ended the way it did. // ============================================================================================= public enum Result { - REACHABLE, // socket connected successfully - NO_NETWORK, // device has no active internet-capable network - HOST_UNREACHABLE // network exists, but host:port could not be reached + REACHABLE, // socket connected successfully + NO_NETWORK, // device has no active internet-capable network + HOST_UNREACHABLE, // network exists, but host:port could not be reached + TRANSMISSION_SUCCESS, // data sent successfully + TRANSMISSION_FAILURE, // data send failed + NO_DATA, // no data to send + SQL_EXCEPTION // SQL error occurred } public interface Callback { @@ -136,7 +151,7 @@ public void shutdown() { // ============================================================================================= // Function: pickWIFI - // Description: Choose new wifi to connect to + // Description: Choose new Wi-Fi to connect to // Parameters: void // Output: void // ============================================================================================= @@ -153,4 +168,115 @@ public void pickWIFI() { appContext.startActivity(GoToSystemWIFI); } } + + // ============================================================================================= + // Function: sendFileToSQLServer + // Description: Asynchronously sends a scouting file to the SQL Server. Callback is on main thread. + // Parameters: in_callback invoked on the main thread with the result + // Output: void + // ============================================================================================= + public void sendFileToSQLServer(@NonNull Callback in_callback) { + executor.execute(() -> { + Result result = sendFileToSQLServerBlocking(); + mainHandler.post(() -> in_callback.onResult(result)); + }); + } + + // ============================================================================================= + // Function: sendFileToSQLServerBlocking + // Description: Synchronous send. Must NOT be called on the main thread. + // Parameters: void + // Output: Result + // ============================================================================================= + @NonNull + public Result sendFileToSQLServerBlocking() { + if (!hasActiveInternet()) { + return Result.NO_NETWORK; + } + + String sql_server = Globals.sp.getString(Constants.Prefs.SQL_SERVER, ""); + String sql_database = Globals.sp.getString(Constants.Prefs.SQL_DATABASE, ""); + String sql_user = Globals.sp.getString(Constants.Prefs.SQL_USER, ""); + String sql_password = Globals.sp.getString(Constants.Prefs.SQL_PASSWORD, ""); + + // Before proceeding, make sure we have settings and a valid connection to the SQL Server + if (sql_server.isEmpty() || sql_database.isEmpty() || sql_user.isEmpty() || sql_password.isEmpty()) { + return Result.TRANSMISSION_FAILURE; + } + + if (!isHostReachable(sql_server, 1433, 3000)) { + return Result.HOST_UNREACHABLE; + } + + String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; + String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; + HashMap line_values = new HashMap<>(); + line_values = getFileAsStringHashMap(); + + // Before proceeding, make sure we have data to send + if (line_values.isEmpty()) { + return Result.NO_DATA; + } + + try (Connection conn = DriverManager.getConnection(url, sql_user, sql_password)) { + conn.setAutoCommit(false); + // Insert the data, line by line + try (java.sql.PreparedStatement ps = conn.prepareStatement(sql)) { + for (String line : line_values.values()) { + ps.setString(1, line); + ps.addBatch(); + } + + ps.executeBatch(); + conn.commit(); + return Result.TRANSMISSION_SUCCESS; + } catch (SQLException e) { + // Rollback the transaction on error + try { + conn.rollback(); + } catch (SQLException ex) { + // ignore + } + return Result.SQL_EXCEPTION; + } + } catch (SQLException e) { + return Result.SQL_EXCEPTION; + } + } + + // ============================================================================================= + // Function: getFileAsStringHashMap + // Description: Initialize the Next Match button + // Parameters: void + // Output: String representing the entire contents of the file + // ============================================================================================= + public HashMap getFileAsStringHashMap() { + String filename = Globals.CurrentCompetitionId + "_" + Globals.TransmitMatchNum + "_" + Globals.CurrentDeviceId + "_" + Globals.TransmitMatchType + ".csv"; + HashMap file_as_hashmap = new HashMap<>(); + String line; + int size = 0; + + try { + // Open up the correct input stream + InputStream is; + DocumentFile df = Globals.output_df.findFile(filename); + assert df != null; + is = appContext.getContentResolver().openInputStream(df.getUri()); + + // Read in the data + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + while ((line = br.readLine()) != null) { + size++; + file_as_hashmap.put(size, line); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + // If we made it this far, add the "F" record at the beginning + file_as_hashmap.put(0, "F," + Globals.CurrentCompetitionId + "," + Globals.TransmitMatchNum + "," + Globals.CurrentDeviceId + "," + Globals.TransmitMatchType); + + return file_as_hashmap; + } } diff --git a/app/src/main/java/com/team3663/scouting_app/utility/Logger.java b/app/src/main/java/com/team3663/scouting_app/utility/Logger.java index bb307c64..fc988f74 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/Logger.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/Logger.java @@ -12,12 +12,16 @@ import com.team3663.scouting_app.config.Globals; import com.team3663.scouting_app.utility.achievements.Achievements; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Objects; // ============================================================================================= @@ -546,6 +550,5 @@ public LoggerEventRow(int in_EventId, int in_Time, int in_X, int in_Y, String in if ((Globals.EventLogger != null) && (!Globals.EventLogger.match_log_events.isEmpty())) prev_time = Globals.EventLogger.match_log_events.get(Globals.EventLogger.match_log_events.size() - 1).LogTime; LogTime = Math.max(in_Time, prev_time); } - } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3e910bc5..a57a6a15 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,19 +1,18 @@ [versions] agp = "9.2.1" junit = "4.13.2" -junitVersion = "1.2.1" -espressoCore = "3.6.1" -appcompat = "1.7.0" -material = "1.12.0" -activity = "1.9.1" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +appcompat = "1.7.1" +material = "1.14.0" +activity = "1.13.0" qrgenVersion = "4.3.0" -constraintlayout = "2.1.4" -preference = "1.2.0" -viewpager2 = "1.1.0" -mssql-jdbc = "12.7.0" -play-services-auth = "21.5.1" +constraintlayout = "2.2.1" +preference = "1.2.1" google-api-client = "2.9.0" google-drive-v3 = "v3-rev20260405-2.0.0" +mssql-jdbc = "12.8.1.jre11" +documentfile = "1.1.0" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -25,9 +24,8 @@ activity = { group = "androidx.activity", name = "activity", version.ref = "acti constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } preference = { group = "androidx.preference", name = "preference", version.ref = "preference" } qr-generator = { group = "com.journeyapps", name = "zxing-android-embedded", version.ref = "qrgenVersion" } -viewpager2 = { group = "androidx.viewpager2", name = "viewpager2", version.ref = "viewpager2" } mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version.ref = "mssql-jdbc" } -play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "play-services-auth" } +documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" } google-api-client = { group = "com.google.api-client", name = "google-api-client-android", version.ref = "google-api-client" } google-drive-services = { group = "com.google.apis", name = "google-api-services-drive", version.ref = "google-drive-v3" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..b1b8ef56b44f16b14dc800fa8103a6d89abb526f 100644 GIT binary patch literal 48462 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 R2np~f1o-$>Q}y+){|A@R9n$~+ literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index deacf87a..eb84db68 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,9 @@ -#Sun Feb 23 15:18:11 PST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c..249efbb0 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,81 +15,114 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# gradlew start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh gradlew +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32..a51ec4f5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,19 +13,22 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,15 +43,15 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -56,34 +59,24 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 -:mainEnd -if "%OS%"=="Windows_NT" endlocal +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% From 43a24db29eaea1b5bbf0f090377d5646d5d33ffa Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Tue, 7 Jul 2026 01:40:14 -0700 Subject: [PATCH 02/13] using jtds instead of mssql.jdbc (it works) --- app/build.gradle.kts | 2 +- app/proguard-rules.pro | 5 +- .../scouting_app/activities/SubmitData.java | 6 ++ .../scouting_app/utility/CPR_Network.java | 68 +++++++++++++++++++ gradle/libs.versions.toml | 4 +- 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6e485b48..09e2b4f3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,7 +54,7 @@ dependencies { implementation(libs.constraintlayout) implementation(libs.qr.generator) implementation(libs.preference) - implementation(libs.mssql.jdbc) + implementation(libs.jtds) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb434..668cb55f 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -18,4 +18,7 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-keep class net.sourceforge.jtds.** { *; } +-dontwarn net.sourceforge.jtds.** \ No newline at end of file diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 36357db9..3ff1fd5c 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -503,15 +503,21 @@ private void initGoogle() { private void initDatabase() { if (!Globals.network.hasActiveInternet()) { submitDataBinding.butSendDatabase.setEnabled(false); + submitDataBinding.butSendDatabase.setClickable(false); + submitDataBinding.butSendDatabase.setBackgroundColor(getColor(R.color.light_grey)); return; } submitDataBinding.butSendDatabase.setOnClickListener(view -> { //Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); submitDataBinding.butSendDatabase.setEnabled(false); + submitDataBinding.butSendDatabase.setClickable(false); + submitDataBinding.butSendDatabase.setBackgroundColor(getColor(R.color.light_grey)); Globals.network.sendFileToSQLServer(result -> { submitDataBinding.butSendDatabase.setEnabled(true); + submitDataBinding.butSendDatabase.setClickable(true); + submitDataBinding.butSendDatabase.setBackgroundColor(getColor(R.color.white)); switch (result) { case TRANSMISSION_SUCCESS: Toast.makeText(this, "Successfully transmitted!", Toast.LENGTH_SHORT).show(); diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index 87a11690..f0562ade 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -208,6 +208,74 @@ public Result sendFileToSQLServerBlocking() { return Result.HOST_UNREACHABLE; } + String url = "jdbc:jtds:sqlserver://" + sql_server + ":1433/" + sql_database + ";loginTimeout=10;socketTimeout=30"; + String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; + HashMap line_values = getFileAsStringHashMap(); + + // Before proceeding, make sure we have data to send + if (line_values.isEmpty()) { + return Result.NO_DATA; + } + + // On Android the driver must be registered explicitly; auto-discovery is unreliable + try { + Class.forName("net.sourceforge.jtds.jdbc.Driver"); + } catch (ClassNotFoundException e) { + return Result.SQL_EXCEPTION; + } + + try (Connection conn = DriverManager.getConnection(url, sql_user, sql_password)) { + conn.setAutoCommit(false); + // Insert the data, line by line + try (java.sql.PreparedStatement ps = conn.prepareStatement(sql)) { + for (String line : line_values.values()) { + ps.setString(1, line); + ps.addBatch(); + } + + ps.executeBatch(); + conn.commit(); + return Result.TRANSMISSION_SUCCESS; + } catch (SQLException e) { + // Rollback the transaction on error + try { + conn.rollback(); + } catch (SQLException ex) { + // ignore + } + return Result.SQL_EXCEPTION; + } + } catch (SQLException e) { + return Result.SQL_EXCEPTION; + } + } + + // ============================================================================================= + // Function: sendFileToSQLServerBlocking + // Description: Synchronous send. Must NOT be called on the main thread. + // Parameters: void + // Output: Result + // ============================================================================================= + @NonNull + public Result sendFileToSQLServerBlockingJDBC() { + if (!hasActiveInternet()) { + return Result.NO_NETWORK; + } + + String sql_server = Globals.sp.getString(Constants.Prefs.SQL_SERVER, ""); + String sql_database = Globals.sp.getString(Constants.Prefs.SQL_DATABASE, ""); + String sql_user = Globals.sp.getString(Constants.Prefs.SQL_USER, ""); + String sql_password = Globals.sp.getString(Constants.Prefs.SQL_PASSWORD, ""); + + // Before proceeding, make sure we have settings and a valid connection to the SQL Server + if (sql_server.isEmpty() || sql_database.isEmpty() || sql_user.isEmpty() || sql_password.isEmpty()) { + return Result.TRANSMISSION_FAILURE; + } + + if (!isHostReachable(sql_server, 1433, 3000)) { + return Result.HOST_UNREACHABLE; + } + String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; HashMap line_values = new HashMap<>(); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a57a6a15..77e1ad4c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,8 +11,8 @@ constraintlayout = "2.2.1" preference = "1.2.1" google-api-client = "2.9.0" google-drive-v3 = "v3-rev20260405-2.0.0" -mssql-jdbc = "12.8.1.jre11" documentfile = "1.1.0" +jtds="1.3.1" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -24,7 +24,7 @@ activity = { group = "androidx.activity", name = "activity", version.ref = "acti constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } preference = { group = "androidx.preference", name = "preference", version.ref = "preference" } qr-generator = { group = "com.journeyapps", name = "zxing-android-embedded", version.ref = "qrgenVersion" } -mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version.ref = "mssql-jdbc" } +jtds = { group = "net.sourceforge.jtds", name = "jtds", version.ref = "jtds"} documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" } google-api-client = { group = "com.google.api-client", name = "google-api-client-android", version.ref = "google-api-client" } google-drive-services = { group = "com.google.apis", name = "google-api-services-drive", version.ref = "google-drive-v3" } From 1b777a6561350b07b34c1f0da18e9d8543c6af88 Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Tue, 7 Jul 2026 17:38:55 -0700 Subject: [PATCH 03/13] initial google code --- app/build.gradle.kts | 2 + .../scouting_app/utility/CPR_Network.java | 93 +++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 09e2b4f3..c24dde07 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,6 +54,8 @@ dependencies { implementation(libs.constraintlayout) implementation(libs.qr.generator) implementation(libs.preference) + implementation(libs.google.api.client) + implementation(libs.google.drive.services) implementation(libs.jtds) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index f0562ade..ca55cc05 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -5,16 +5,22 @@ import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.provider.Settings; +import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.documentfile.provider.DocumentFile; import com.team3663.scouting_app.config.Constants; import com.team3663.scouting_app.config.Globals; +import com.google.api.client.http.InputStreamContent; +import com.google.api.services.drive.Drive; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -24,6 +30,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.util.Collections; import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -39,6 +46,7 @@ public class CPR_Network { private final Context appContext; private final ExecutorService executor; private final Handler mainHandler; + private static final String GOOGLE_TAG = "DriveUploadHelper"; // ============================================================================================= // Why a reachability check ended the way it did. @@ -347,4 +355,89 @@ public HashMap getFileAsStringHashMap() { return file_as_hashmap; } + + // ============================================================================================= + // Function: uploadToGoogle + // Description: Asynchronously copy the file to a Google Drive + // Parameters: in_host hostname or IP of the remote machine + // in_port port the remote service listens on (e.g. 8080, 443, 22) + // in_timeoutMs socket connect timeout in milliseconds + // in_callback invoked on the main thread with the result + // Output: void + // ============================================================================================= + public void uploadToGoogle(@NonNull Context in_context) { + final String filename = Globals.CurrentCompetitionId + "_" + Globals.TransmitMatchNum + "_" + Globals.CurrentDeviceId + "_" + Globals.TransmitMatchType + ".csv"; + DocumentFile df = Globals.output_df.findFile(filename); + + // validate the file exists + if (df==null || !df.exists() || !df.isFile()) { + Toast.makeText(in_context, "Google Upload Failed: File not found", Toast.LENGTH_LONG).show(); + return; + } + + final long localSize = df.length(); + final Uri sourceUri = df.getUri(); + + executor.execute(() -> { + try { + // validate connectivity + if (!hasActiveInternet()) { + Toast.makeText(in_context, "Google Upload Failed: No Internet Connection", Toast.LENGTH_LONG).show(); + return; + } + + String mimeType = in_context.getContentResolver().getType(sourceUri); + if (mimeType == null) { + Toast.makeText(in_context, "Google Upload Failed: File Type Not Found", Toast.LENGTH_LONG).show(); + return; + } + + com.google.api.services.drive.model.File fileMetadata = new com.google.api.services.drive.model.File(); + fileMetadata.setName(filename); + fileMetadata.setParents(Collections.singletonList(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE, ""))); + + InputStream inputStream = in_context.getContentResolver().openInputStream(sourceUri); + if (inputStream == null) { + Toast.makeText(in_context, "Google Upload Failed: Unable to open file", Toast.LENGTH_LONG).show(); + return; + } + + InputStreamContent fileContent = new InputStreamContent(mimeType, inputStream); + if (localSize > 0) { + fileContent.setLength(localSize); + } + + com.google.api.services.drive.model.File uploadedFile = driveService.files() + .create(fileMetadata, fileContent) + .setFields("id, name, size, trashed") + .execute(); + + if (uploadedFile == null) { + Toast.makeText(in_context, "Google Upload Failed: Error transferring file", Toast.LENGTH_LONG).show(); + return; + } + + // Validate upload + com.google.api.services.drive.model.File remoteFile = driveService.files() + .get(uploadedFile.getId()) + .setFields("id, size, trashed") + .execute(); + + if (remoteFile == null || remoteFile.getId() == null || Boolean.TRUE.equals(remoteFile.getTrashed())) { + Toast.makeText(in_context, "Google Upload Failed: Unable to find remote file", Toast.LENGTH_LONG).show(); + return; + } + + if (remoteFile.getSize() == null || remoteFile.getSize() != localSize) { + Toast.makeText(in_context, "Google Upload Failed: File size mismatch", Toast.LENGTH_LONG).show(); + return; + } + + Toast.makeText(in_context, "Google Upload Successful", Toast.LENGTH_LONG).show(); + } + catch (Exception e) { + Toast.makeText(in_context, "Google Upload Failed: Exception occurred", Toast.LENGTH_LONG).show(); + } + }); + } } From 2335fc2c724ce144357f5e24eccc51415a361b9b Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Wed, 8 Jul 2026 01:29:25 -0700 Subject: [PATCH 04/13] keep the SQL jdbc string --- .../java/com/team3663/scouting_app/utility/CPR_Network.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index ca55cc05..f311b9dc 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -12,7 +12,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.documentfile.provider.DocumentFile; import com.team3663.scouting_app.config.Constants; @@ -216,6 +215,7 @@ public Result sendFileToSQLServerBlocking() { return Result.HOST_UNREACHABLE; } + // String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; String url = "jdbc:jtds:sqlserver://" + sql_server + ":1433/" + sql_database + ";loginTimeout=10;socketTimeout=30"; String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; HashMap line_values = getFileAsStringHashMap(); From 27470bb45b3975c4f7f035c21808746baaf2f9f7 Mon Sep 17 00:00:00 2001 From: Jeff Stammler <85592424+Jeff-Stammler@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:07:58 -0700 Subject: [PATCH 05/13] claude helped with google --- app/proguard-rules.pro | 17 +++- .../scouting_app/activities/SubmitData.java | 72 ++++++++++++++- .../scouting_app/utility/CPR_Network.java | 91 ++++++++++++++++--- gradle/libs.versions.toml | 2 + 4 files changed, 166 insertions(+), 16 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 668cb55f..cc4461fd 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -21,4 +21,19 @@ #-renamesourcefileattribute SourceFile -keep class net.sourceforge.jtds.** { *; } --dontwarn net.sourceforge.jtds.** \ No newline at end of file +-dontwarn net.sourceforge.jtds.** + +# Google API/Drive client (google-api-client ships no consumer rules and maps JSON via +# reflection on @Key-annotated fields; R8 would otherwise strip/rename them and break uploads). +-keepattributes Signature,*Annotation*,EnclosingMethod +-keep class com.google.api.client.** { *; } +-keep class com.google.api.services.drive.** { *; } +-keepclassmembers class * { @com.google.api.client.util.Key ; } +-dontwarn com.google.api.client.** +-dontwarn com.google.api.services.drive.** +-dontwarn org.apache.http.** +-dontwarn javax.** + +# Gson (used by GsonFactory to (de)serialize the Drive model classes) +-keep class com.google.gson.** { *; } +-dontwarn com.google.gson.** \ No newline at end of file diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 3ff1fd5c..5a94539e 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -19,16 +19,24 @@ import android.widget.Toast; import androidx.activity.EdgeToEdge; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.Scope; import com.team3663.scouting_app.R; import com.team3663.scouting_app.config.Constants; import com.team3663.scouting_app.config.Globals; import com.team3663.scouting_app.databinding.SubmitDataBinding; +import com.team3663.scouting_app.utility.CPR_Network; import com.team3663.scouting_app.utility.Logger; import com.team3663.scouting_app.utility.achievements.Achievements; @@ -48,6 +56,7 @@ public class SubmitData extends AppCompatActivity { private static MediaPlayer media; private ConnectivityManager connectivityManager; private ConnectivityManager.NetworkCallback networkCallback; + private ActivityResultLauncher googleSignInLauncher; @SuppressLint({"SetTextI18n", "MissingInflatedId"}) @Override @@ -63,6 +72,9 @@ protected void onCreate(Bundle in_savedInstanceState) { return insets; }); + // Register the Google sign-in launcher before the activity is STARTED + initGoogleSignIn(); + // Initialize activity components that need the Logger initAchievements(); @@ -490,10 +502,68 @@ private void initGoogle() { } submitDataBinding.butSendGoogle.setOnClickListener(view -> { - Toast.makeText(this, "Coming Soon...", Toast.LENGTH_SHORT).show(); + Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + + // If the Drive service is already built this session, upload straight away + if (Globals.network.isDriveServiceReady()) { + Globals.network.uploadToGoogle(this); + return; + } + + // Reuse an existing sign-in if it already granted the Drive scope + Scope driveScope = new Scope(CPR_Network.GOOGLE_DRIVE_SCOPE); + GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(this); + if (GoogleSignIn.hasPermissions(last, driveScope)) { + onGoogleSignedIn(last); + return; + } + + // Otherwise start the interactive sign-in / consent flow + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestScopes(driveScope) + .build(); + googleSignInLauncher.launch(GoogleSignIn.getClient(this, gso).getSignInIntent()); }); } + // ============================================================================================= + // Function: initGoogleSignIn + // Description: Register the launcher that receives the result of the Google sign-in flow. + // Parameters: void + // Output: void + // ============================================================================================= + private void initGoogleSignIn() { + googleSignInLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + try { + GoogleSignInAccount account = GoogleSignIn + .getSignedInAccountFromIntent(result.getData()) + .getResult(ApiException.class); + onGoogleSignedIn(account); + } catch (ApiException e) { + Toast.makeText(this, "Google sign-in failed", Toast.LENGTH_SHORT).show(); + } + }); + } + + // ============================================================================================= + // Function: onGoogleSignedIn + // Description: Build the Drive service from the signed-in account and start the upload. + // Parameters: in_account the account returned from Google sign-in + // Output: void + // ============================================================================================= + private void onGoogleSignedIn(GoogleSignInAccount in_account) { + if (in_account == null || in_account.getAccount() == null) { + Toast.makeText(this, "Google sign-in failed", Toast.LENGTH_SHORT).show(); + return; + } + + Globals.network.initDriveService(in_account.getAccount()); + Globals.network.uploadToGoogle(this); + } + // ============================================================================================= // Function: initDatabase // Description: Initialize the Database field diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index f311b9dc..699c70ec 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -1,5 +1,6 @@ package com.team3663.scouting_app.utility; +import android.accounts.Account; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; @@ -17,8 +18,12 @@ import com.team3663.scouting_app.config.Constants; import com.team3663.scouting_app.config.Globals; +import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.http.InputStreamContent; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; +import com.google.api.services.drive.DriveScopes; import java.io.BufferedReader; import java.io.IOException; @@ -46,6 +51,12 @@ public class CPR_Network { private final ExecutorService executor; private final Handler mainHandler; private static final String GOOGLE_TAG = "DriveUploadHelper"; + // drive.file is a non-sensitive scope (no OAuth verification needed). It grants access only to + // files this app creates, which is all we do here: create a file in the shared folder (any + // signed-in account can write to it via the folder's "anyone with the link can edit" grant). + // Note: this scope does NOT allow listing/reading other files in that folder. + public static final String GOOGLE_DRIVE_SCOPE = DriveScopes.DRIVE_FILE; + private Drive driveService; // ============================================================================================= // Why a reachability check ended the way it did. @@ -356,22 +367,70 @@ public HashMap getFileAsStringHashMap() { return file_as_hashmap; } + // ============================================================================================= + // Function: initDriveService + // Description: Build the Google Drive service from a signed-in Google account. Must be called + // (with a Drive-scoped account) before uploadToGoogle(). Uploads run as this + // user, so any Drive folder shared with them (including one they don't own) is + // reachable by folder id. + // Parameters: in_account the signed-in Google account with GOOGLE_DRIVE_SCOPE granted + // Output: void + // ============================================================================================= + public void initDriveService(@NonNull Account in_account) { + GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2( + appContext, Collections.singletonList(GOOGLE_DRIVE_SCOPE)); + credential.setSelectedAccount(in_account); + + driveService = new Drive.Builder( + new NetHttpTransport(), + GsonFactory.getDefaultInstance(), + credential) + .setApplicationName("CPR Scouting App") + .build(); + } + + // ============================================================================================= + // Function: isDriveServiceReady + // Description: Has a Drive service been built from a signed-in account yet? + // Parameters: void + // Output: boolean + // ============================================================================================= + public boolean isDriveServiceReady() { + return driveService != null; + } + + // ============================================================================================= + // Function: showToast + // Description: Post a Toast to the main thread (safe to call from a background thread). + // Parameters: in_context context used to build the Toast + // in_message text to display + // in_duration Toast.LENGTH_SHORT or Toast.LENGTH_LONG + // Output: void + // ============================================================================================= + private void showToast(@NonNull Context in_context, @NonNull String in_message, int in_duration) { + mainHandler.post(() -> Toast.makeText(in_context, in_message, in_duration).show()); + } + // ============================================================================================= // Function: uploadToGoogle - // Description: Asynchronously copy the file to a Google Drive - // Parameters: in_host hostname or IP of the remote machine - // in_port port the remote service listens on (e.g. 8080, 443, 22) - // in_timeoutMs socket connect timeout in milliseconds - // in_callback invoked on the main thread with the result + // Description: Asynchronously copy the file to the shared Google Drive folder. initDriveService() + // must have been called first. Feedback is shown via Toast on the main thread. + // Parameters: in_context context used for content resolution and Toast feedback // Output: void // ============================================================================================= public void uploadToGoogle(@NonNull Context in_context) { + // We must have a Drive service (built from a signed-in account) before we can upload + if (driveService == null) { + showToast(in_context, "Google Upload Failed: Not signed in to Google", Toast.LENGTH_LONG); + return; + } + final String filename = Globals.CurrentCompetitionId + "_" + Globals.TransmitMatchNum + "_" + Globals.CurrentDeviceId + "_" + Globals.TransmitMatchType + ".csv"; DocumentFile df = Globals.output_df.findFile(filename); // validate the file exists if (df==null || !df.exists() || !df.isFile()) { - Toast.makeText(in_context, "Google Upload Failed: File not found", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: File not found", Toast.LENGTH_LONG); return; } @@ -382,13 +441,13 @@ public void uploadToGoogle(@NonNull Context in_context) { try { // validate connectivity if (!hasActiveInternet()) { - Toast.makeText(in_context, "Google Upload Failed: No Internet Connection", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: No Internet Connection", Toast.LENGTH_LONG); return; } String mimeType = in_context.getContentResolver().getType(sourceUri); if (mimeType == null) { - Toast.makeText(in_context, "Google Upload Failed: File Type Not Found", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: File Type Not Found", Toast.LENGTH_LONG); return; } @@ -398,7 +457,7 @@ public void uploadToGoogle(@NonNull Context in_context) { InputStream inputStream = in_context.getContentResolver().openInputStream(sourceUri); if (inputStream == null) { - Toast.makeText(in_context, "Google Upload Failed: Unable to open file", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: Unable to open file", Toast.LENGTH_LONG); return; } @@ -407,36 +466,40 @@ public void uploadToGoogle(@NonNull Context in_context) { fileContent.setLength(localSize); } + // setSupportsAllDrives(true) is required when the parent folder lives in a Shared + // Drive (or was shared to us from another account). com.google.api.services.drive.model.File uploadedFile = driveService.files() .create(fileMetadata, fileContent) + .setSupportsAllDrives(true) .setFields("id, name, size, trashed") .execute(); if (uploadedFile == null) { - Toast.makeText(in_context, "Google Upload Failed: Error transferring file", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: Error transferring file", Toast.LENGTH_LONG); return; } // Validate upload com.google.api.services.drive.model.File remoteFile = driveService.files() .get(uploadedFile.getId()) + .setSupportsAllDrives(true) .setFields("id, size, trashed") .execute(); if (remoteFile == null || remoteFile.getId() == null || Boolean.TRUE.equals(remoteFile.getTrashed())) { - Toast.makeText(in_context, "Google Upload Failed: Unable to find remote file", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: Unable to find remote file", Toast.LENGTH_LONG); return; } if (remoteFile.getSize() == null || remoteFile.getSize() != localSize) { - Toast.makeText(in_context, "Google Upload Failed: File size mismatch", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: File size mismatch", Toast.LENGTH_LONG); return; } - Toast.makeText(in_context, "Google Upload Successful", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Successful", Toast.LENGTH_LONG); } catch (Exception e) { - Toast.makeText(in_context, "Google Upload Failed: Exception occurred", Toast.LENGTH_LONG).show(); + showToast(in_context, "Google Upload Failed: Exception occurred", Toast.LENGTH_LONG); } }); } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 77e1ad4c..c0cc5fcb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ constraintlayout = "2.2.1" preference = "1.2.1" google-api-client = "2.9.0" google-drive-v3 = "v3-rev20260405-2.0.0" +play-services-auth = "21.3.0" documentfile = "1.1.0" jtds="1.3.1" @@ -28,6 +29,7 @@ jtds = { group = "net.sourceforge.jtds", name = "jtds", version.ref = "jtds"} documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" } google-api-client = { group = "com.google.api-client", name = "google-api-client-android", version.ref = "google-api-client" } google-drive-services = { group = "com.google.apis", name = "google-api-services-drive", version.ref = "google-drive-v3" } +play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "play-services-auth" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } \ No newline at end of file From 1fc26d1d8274411baf50339bc0e80ed7dd9360cc Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Wed, 8 Jul 2026 15:15:26 -0700 Subject: [PATCH 06/13] sync with my computer + gradle+libs update --- .gitignore | 3 +++ app/build.gradle.kts | 25 +++++++++++++++++++++++++ gradle/libs.versions.toml | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index aa724b77..ba0375d9 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ .externalNativeBuild .cxx local.properties +keystore.properties +*.jks +*.keystore diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c24dde07..daaa195f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,6 @@ +import java.io.FileInputStream +import java.util.Properties + plugins { alias(libs.plugins.android.application) id("base") @@ -7,6 +10,13 @@ var versionMajor = 4 var versionMinor = 0 var versionPatch = 0 +val keystorePropertiesFile = rootProject.file("keystore.properties") +val keystoreProperties = Properties().apply { + if (keystorePropertiesFile.exists()) { + load (FileInputStream(keystorePropertiesFile)) + } +} + configure { namespace = "com.team3663.scouting_app" compileSdk = 37 @@ -25,6 +35,17 @@ configure { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } + signingConfigs { + create("release") { + if (keystorePropertiesFile.exists()) { + storeFile = file(keystoreProperties.getProperty("storeFile")) + storePassword = keystoreProperties.getProperty("storePassword") + keyAlias = keystoreProperties.getProperty("keyAlias") + keyPassword = keystoreProperties.getProperty("keyPassword") + } + } + } + buildTypes { getByName("release") { isMinifyEnabled = true @@ -33,6 +54,9 @@ configure { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro", ) + if (keystorePropertiesFile.exists()) { + signingConfig = signingConfigs.getByName("release") + } } } compileOptions { @@ -56,6 +80,7 @@ dependencies { implementation(libs.preference) implementation(libs.google.api.client) implementation(libs.google.drive.services) + implementation(libs.play.services.auth) implementation(libs.jtds) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c0cc5fcb..865435d1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ constraintlayout = "2.2.1" preference = "1.2.1" google-api-client = "2.9.0" google-drive-v3 = "v3-rev20260405-2.0.0" -play-services-auth = "21.3.0" +play-services-auth = "21.6.0" documentfile = "1.1.0" jtds="1.3.1" From b25ab9f8a27babfec00b8c82e4a16ae378b568ef Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Tue, 4 Aug 2026 11:41:35 -0700 Subject: [PATCH 07/13] jdbc updates --- app/build.gradle.kts | 9 ++++++++- .../com/team3663/scouting_app/activities/SubmitData.java | 6 ++++-- .../com/team3663/scouting_app/utility/CPR_Network.java | 1 + gradle/libs.versions.toml | 8 +++++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index daaa195f..9ea05dbd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,6 +64,12 @@ configure { targetCompatibility = JavaVersion.VERSION_11 } + packaging { + resources { + excludes += "META-INF/INDEX.LIST" + excludes += "META-INF/DEPENDENCIES" + } + } } base { @@ -81,7 +87,8 @@ dependencies { implementation(libs.google.api.client) implementation(libs.google.drive.services) implementation(libs.play.services.auth) - implementation(libs.jtds) +// implementation(libs.jtds) + implementation(libs.mssql) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 5a94539e..6943fff9 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -395,8 +395,10 @@ public void onNothingSelected(AdapterView adapterView) { adp_Match.setDropDownViewResource(R.layout.cpr_spinner_item); submitDataBinding.spinnerMatch.setAdapter(adp_Match); // Set the selection (if there are any) to the latest match (largest value in the list) - if (adp_Match.getCount() > 0) submitDataBinding.spinnerMatch.setSelection(adp_Match.getCount() - 1, true); - Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + if (adp_Match.getCount() > 0) { + submitDataBinding.spinnerMatch.setSelection(adp_Match.getCount() - 1, true); + Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + } } // ============================================================================================= diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index 699c70ec..5f0b929d 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -296,6 +296,7 @@ public Result sendFileToSQLServerBlockingJDBC() { } String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; + // String url = "jdbc:jtds:sqlserver://" + sql_server + ":1433/" + sql_database + ";loginTimeout=10;socketTimeout=30"; String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; HashMap line_values = new HashMap<>(); line_values = getFileAsStringHashMap(); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 865435d1..c5910cce 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,13 +7,14 @@ appcompat = "1.7.1" material = "1.14.0" activity = "1.13.0" qrgenVersion = "4.3.0" -constraintlayout = "2.2.1" +constraintlayout = "2.2.2" preference = "1.2.1" google-api-client = "2.9.0" google-drive-v3 = "v3-rev20260405-2.0.0" play-services-auth = "21.6.0" documentfile = "1.1.0" -jtds="1.3.1" +#jtds="1.3.1" +mssql-jdbc="13.5.1.jre11-preview" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -25,11 +26,12 @@ activity = { group = "androidx.activity", name = "activity", version.ref = "acti constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } preference = { group = "androidx.preference", name = "preference", version.ref = "preference" } qr-generator = { group = "com.journeyapps", name = "zxing-android-embedded", version.ref = "qrgenVersion" } -jtds = { group = "net.sourceforge.jtds", name = "jtds", version.ref = "jtds"} +#jtds = { group = "net.sourceforge.jtds", name = "jtds", version.ref = "jtds"} documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" } google-api-client = { group = "com.google.api-client", name = "google-api-client-android", version.ref = "google-api-client" } google-drive-services = { group = "com.google.apis", name = "google-api-services-drive", version.ref = "google-drive-v3" } play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "play-services-auth" } +mssql = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version.ref = "mssql-jdbc"} [plugins] android-application = { id = "com.android.application", version.ref = "agp" } \ No newline at end of file From 35dbdacc01cdaf1ae8065571410447b84c9e259a Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Mon, 17 Aug 2026 20:34:18 -0700 Subject: [PATCH 08/13] final --- app/build.gradle.kts | 1 - .../scouting_app/activities/Settings.java | 32 ++- .../scouting_app/config/Constants.java | 5 +- .../scouting_app/fragments/SettingsPage1.java | 38 +++- .../scouting_app/fragments/SettingsPage2.java | 50 ++--- .../scouting_app/fragments/SettingsPage3.java | 1 - .../scouting_app/fragments/SettingsPage4.java | 202 ++++++++++++++++++ .../fragments/SettingsPagerAdapter.java | 11 +- .../scouting_app/utility/CPR_Network.java | 9 +- .../res/layout/fragment_settings_page1.xml | 86 ++++++-- .../res/layout/fragment_settings_page2.xml | 84 +++----- .../res/layout/fragment_settings_page3.xml | 28 --- .../res/layout/fragment_settings_page4.xml | 146 +++++++++++++ app/src/main/res/values/strings_settings.xml | 3 +- gradle/libs.versions.toml | 6 +- 15 files changed, 532 insertions(+), 170 deletions(-) create mode 100644 app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java create mode 100644 app/src/main/res/layout/fragment_settings_page4.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9ea05dbd..06dc7bc5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -87,7 +87,6 @@ dependencies { implementation(libs.google.api.client) implementation(libs.google.drive.services) implementation(libs.play.services.auth) -// implementation(libs.jtds) implementation(libs.mssql) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) diff --git a/app/src/main/java/com/team3663/scouting_app/activities/Settings.java b/app/src/main/java/com/team3663/scouting_app/activities/Settings.java index 71e0d8c2..660a67c6 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/Settings.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/Settings.java @@ -11,6 +11,7 @@ import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; +import androidx.fragment.app.Fragment; import com.team3663.scouting_app.R; import com.team3663.scouting_app.config.*; @@ -70,6 +71,7 @@ private void SaveSettings() { SettingsPage1 fragmentPage1 = adapter.getFragmentPage1(); SettingsPage2 fragmentPage2 = adapter.getFragmentPage2(); SettingsPage3 fragmentPage3 = adapter.getFragmentPage3(); + SettingsPage4 fragmentPage4 = adapter.getFragmentPage4(); // Page1 Settings if (fragmentPage1 != null && fragmentPage1.binding != null) { @@ -92,9 +94,11 @@ private void SaveSettings() { Globals.spe.putString(Constants.Prefs.SCOUTING_TEAM, ScoutingTeam); } - int NumMatches = Integer.parseInt(fragmentPage1.binding.editNumMatches.getText().toString()); - if (NumMatches < 1) NumMatches = 1; - Globals.spe.putInt(Constants.Prefs.NUM_MATCHES, NumMatches); + Globals.CurrentPrefTeamPos = fragmentPage1.binding.spinnerPrefTeamPos.getSelectedItemPosition(); + Globals.spe.putInt(Constants.Prefs.PREF_TEAM_POS, Globals.CurrentPrefTeamPos); + + Globals.CurrentFieldOrientationPos = fragmentPage1.binding.spinnerOrientation.getSelectedItemPosition(); + Globals.spe.putInt(Constants.Prefs.PREF_ORIENTATION, Globals.CurrentFieldOrientationPos); } // Page2 Settings @@ -104,23 +108,18 @@ private void SaveSettings() { Globals.spe.putInt(Constants.Prefs.COLOR_CONTEXT_MENU, ColorId); } - Globals.CurrentPrefTeamPos = fragmentPage2.binding.spinnerPrefTeamPos.getSelectedItemPosition(); - Globals.spe.putInt(Constants.Prefs.PREF_TEAM_POS, Globals.CurrentPrefTeamPos); - int CurrentQRSize = Integer.parseInt(fragmentPage2.binding.editQRSize.getText().toString()); Globals.spe.putInt(Constants.Prefs.QR_SIZE, CurrentQRSize); - Globals.CurrentFieldOrientationPos = fragmentPage2.binding.spinnerOrientation.getSelectedItemPosition(); - Globals.spe.putInt(Constants.Prefs.PREF_ORIENTATION, Globals.CurrentFieldOrientationPos); + int NumMatches = Integer.parseInt(fragmentPage2.binding.editNumMatches.getText().toString()); + if (NumMatches < 1) NumMatches = 1; + Globals.spe.putInt(Constants.Prefs.NUM_MATCHES, NumMatches); } // Page3 Settings if (fragmentPage3 != null && fragmentPage3.binding != null) { Editable userField; - userField = fragmentPage3.binding.editGoogleDrive.getText(); - Globals.spe.putString(Constants.Prefs.GOOGLE_DRIVE, (userField != null) ? userField.toString() : ""); - userField = fragmentPage3.binding.editServer.getText(); Globals.spe.putString(Constants.Prefs.SQL_SERVER, (userField != null) ? userField.toString() : ""); @@ -134,6 +133,17 @@ private void SaveSettings() { Globals.spe.putString(Constants.Prefs.SQL_PASSWORD, (userField != null) ? userField.toString() : ""); } + // Page4 Settings + if (fragmentPage4 != null && fragmentPage4.binding != null) { + Editable userField; + + userField = fragmentPage4.binding.editGoogleUpload.getText(); + Globals.spe.putString(Constants.Prefs.GOOGLE_DRIVE_UPLOAD, (userField != null) ? userField.toString() : ""); + + userField = fragmentPage4.binding.editGoogleDownload.getText(); + Globals.spe.putString(Constants.Prefs.GOOGLE_DRIVE_DOWNLOAD, (userField != null) ? userField.toString() : ""); + } + Globals.spe.apply(); setResult(RESULT_OK, intent); finish(); diff --git a/app/src/main/java/com/team3663/scouting_app/config/Constants.java b/app/src/main/java/com/team3663/scouting_app/config/Constants.java index 9b689a85..662879ba 100644 --- a/app/src/main/java/com/team3663/scouting_app/config/Constants.java +++ b/app/src/main/java/com/team3663/scouting_app/config/Constants.java @@ -121,7 +121,8 @@ public static class Prefs { public static final String STORAGE_URI = "StorageURI"; public static final String PREF_ORIENTATION = "PreferredFieldOrientation"; public static final String QR_SIZE = "PreferredQRSize"; - public static final String GOOGLE_DRIVE = "PreferredGoogleDrive"; + public static final String GOOGLE_DRIVE_UPLOAD = "PreferredGoogleDriveUpload"; + public static final String GOOGLE_DRIVE_DOWNLOAD = "PreferredGoogleDriveDownload"; public static final String SQL_SERVER = "PreferredSqlServer"; public static final String SQL_DATABASE = "PreferredSqlDatabase"; public static final String SQL_USER = "PreferredSqlUser"; @@ -132,6 +133,8 @@ public static class Settings { public static final String[] PREF_TEAM_POS = new String[]{"No Preference", "Blue 1", "Blue 2", "Blue 3", "Red 1", "Red 2", "Red 3"}; public static final String[] PREF_FIELD_ORIENTATION = new String[]{"Automatic", "Blue On Left", "Red On Left"}; public static final String RELOAD_DATA_KEY = "ReloadData"; + public static final String DEFAULT_GOOGLE_UPLOAD = "1DB3Dg9N-4zbOxV28Sor-YJrWuoK_OfY8"; + public static final String DEFAULT_GOOGLE_DOWNLOAD = "12up9moFxnuKezANiMV_ocmwmGz4ONA-v"; } public static class AppLaunch { diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java index d95ba990..6bebc319 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java @@ -32,7 +32,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat initCompetition(); initDevice(); initScoutingTeam(); - initNumMatches(); + initFieldOrientation(); + initPrefTeamPos(); } // ============================================================================================= @@ -129,14 +130,39 @@ private void initScoutingTeam() { } // ============================================================================================= - // Function: initNumMatches - // Description: Initialize the Number of Matches to Keep field + // Function: initFieldOrientation + // Description: Initialize the Preferred Field Orientation field // Parameters: void // Output: void // ============================================================================================= - private void initNumMatches() { - // Restore number of files to keep from saved preferences - binding.editNumMatches.setText(String.valueOf(Globals.sp.getInt(Constants.Prefs.NUM_MATCHES, 50))); + private void initFieldOrientation() { + // Adds PreferredFieldOrientation information to spinner + ArrayAdapter adp_PrefOrientation = new ArrayAdapter<>(requireContext(), + R.layout.cpr_spinner, Constants.Settings.PREF_FIELD_ORIENTATION); + adp_PrefOrientation.setDropDownViewResource(R.layout.cpr_spinner_item); + binding.spinnerOrientation.setAdapter(adp_PrefOrientation); + + // Set the selection (if there is one) to the saved one + int savedPrefOrientation = Globals.sp.getInt(Constants.Prefs.PREF_ORIENTATION, 0); + binding.spinnerOrientation.setSelection(savedPrefOrientation, true); + } + + // ============================================================================================= + // Function: initPrefTeamPos + // Description: Initialize the Preferred Team Position field + // Parameters: void + // Output: void + // ============================================================================================= + private void initPrefTeamPos() { + // Adds PreferredTeamPosition information to spinner + ArrayAdapter adp_PrefTeamPos = new ArrayAdapter<>(requireContext(), + R.layout.cpr_spinner, Constants.Settings.PREF_TEAM_POS); + adp_PrefTeamPos.setDropDownViewResource(R.layout.cpr_spinner_item); + binding.spinnerPrefTeamPos.setAdapter(adp_PrefTeamPos); + + // Set the selection (if there is one) to the saved one + int savedPrefTeamPos = Globals.sp.getInt(Constants.Prefs.PREF_TEAM_POS, 0); + binding.spinnerPrefTeamPos.setSelection(savedPrefTeamPos, true); } @Override diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java index e637f300..071af679 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java @@ -29,10 +29,9 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initColors(); - initFieldOrientation(); - initPrefTeamPos(); initQRSize(); initShadowMode(); + initNumMatches(); } // ============================================================================================= @@ -64,42 +63,6 @@ public void onNothingSelected(AdapterView parent) {} }); } - // ============================================================================================= - // Function: initFieldOrientation - // Description: Initialize the Preferred Field Orientation field - // Parameters: void - // Output: void - // ============================================================================================= - private void initFieldOrientation() { - // Adds PreferredFieldOrientation information to spinner - ArrayAdapter adp_PrefOrientation = new ArrayAdapter<>(requireContext(), - R.layout.cpr_spinner, Constants.Settings.PREF_FIELD_ORIENTATION); - adp_PrefOrientation.setDropDownViewResource(R.layout.cpr_spinner_item); - binding.spinnerOrientation.setAdapter(adp_PrefOrientation); - - // Set the selection (if there is one) to the saved one - int savedPrefOrientation = Globals.sp.getInt(Constants.Prefs.PREF_ORIENTATION, 0); - binding.spinnerOrientation.setSelection(savedPrefOrientation, true); - } - - // ============================================================================================= - // Function: initPrefTeamPos - // Description: Initialize the Preferred Team Position field - // Parameters: void - // Output: void - // ============================================================================================= - private void initPrefTeamPos() { - // Adds PreferredTeamPosition information to spinner - ArrayAdapter adp_PrefTeamPos = new ArrayAdapter<>(requireContext(), - R.layout.cpr_spinner, Constants.Settings.PREF_TEAM_POS); - adp_PrefTeamPos.setDropDownViewResource(R.layout.cpr_spinner_item); - binding.spinnerPrefTeamPos.setAdapter(adp_PrefTeamPos); - - // Set the selection (if there is one) to the saved one - int savedPrefTeamPos = Globals.sp.getInt(Constants.Prefs.PREF_TEAM_POS, 0); - binding.spinnerPrefTeamPos.setSelection(savedPrefTeamPos, true); - } - // ============================================================================================= // Function: initQRSize // Description: Initialize the QR Size field @@ -128,6 +91,17 @@ private void initShadowMode() { binding.checkboxShadowMode.setOnCheckedChangeListener((buttonView, isChecked) -> Globals.isShadowMode = isChecked); } + // ============================================================================================= + // Function: initNumMatches + // Description: Initialize the Number of Matches to Keep field + // Parameters: void + // Output: void + // ============================================================================================= + private void initNumMatches() { + // Restore number of files to keep from saved preferences + binding.editNumMatches.setText(String.valueOf(Globals.sp.getInt(Constants.Prefs.NUM_MATCHES, 50))); + } + @Override public void onDestroyView() { super.onDestroyView(); diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage3.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage3.java index db706230..263fca20 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage3.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage3.java @@ -57,7 +57,6 @@ public void onDestroyView() { // Output: void // ============================================================================================= private void initFields() { - binding.editGoogleDrive.setText(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE, "1DB3Dg9N-4zbOxV28Sor-YJrWuoK_OfY8")); binding.editServer.setText(Globals.sp.getString(Constants.Prefs.SQL_SERVER, "mssql01.cpr3663.io")); binding.editDatabase.setText(Globals.sp.getString(Constants.Prefs.SQL_DATABASE, "CPR_Scouting_2025")); binding.editUser.setText(Globals.sp.getString(Constants.Prefs.SQL_USER, "CPR_Tablet")); diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java new file mode 100644 index 00000000..010e4852 --- /dev/null +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java @@ -0,0 +1,202 @@ +package com.team3663.scouting_app.fragments; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.team3663.scouting_app.R; +import com.team3663.scouting_app.config.Constants; +import com.team3663.scouting_app.config.Globals; +import com.team3663.scouting_app.databinding.FragmentSettingsPage4Binding; + +public class SettingsPage4 extends Fragment { + public FragmentSettingsPage4Binding binding; + private ConnectivityManager connectivityManager; + private ConnectivityManager.NetworkCallback networkCallback; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentSettingsPage4Binding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + initNetwork(); + initChooseWifi(); + initRefresh(); + initFields(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + // Important: Unregister to avoid memory leaks + if (connectivityManager != null && networkCallback != null) { + connectivityManager.unregisterNetworkCallback(networkCallback); + } + } + + // ============================================================================================= + // Function: initFields + // Description: Initialize the Fields on the fragment + // Parameters: void + // Output: void + // ============================================================================================= + private void initFields() { + String pref_Upload = Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE_UPLOAD, ""); + String pref_Download = Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE_DOWNLOAD, ""); + + // Set up fields. If the Google folders are either empty or happen to match the default, turn on the default checkbox, + // otherwise allow them to be edited. + if (pref_Upload.isEmpty() || pref_Upload.equals(Constants.Settings.DEFAULT_GOOGLE_UPLOAD)) { + binding.editGoogleUpload.setText(Constants.Settings.DEFAULT_GOOGLE_UPLOAD); + binding.butDefaultUpload.setChecked(true); + binding.editGoogleUpload.setEnabled(false); + } else { + binding.editGoogleUpload.setText(pref_Upload); + binding.butDefaultUpload.setChecked(false); + binding.editGoogleUpload.setEnabled(true); + } + + if (pref_Download.isEmpty() || pref_Download.equals(Constants.Settings.DEFAULT_GOOGLE_DOWNLOAD)) { + binding.editGoogleDownload.setText(Constants.Settings.DEFAULT_GOOGLE_DOWNLOAD); + binding.butDefaultDownload.setChecked(true); + binding.editGoogleDownload.setEnabled(false); + } else { + binding.editGoogleDownload.setText(pref_Upload); + binding.butDefaultDownload.setChecked(false); + binding.editGoogleDownload.setEnabled(true); + } + + // If we default the folder, set the checkbox to checked and disable the edit field and set the default folder name + binding.butDefaultUpload.setOnClickListener(view -> { + if (binding.butDefaultUpload.isChecked()) { + binding.editGoogleUpload.setText(Constants.Settings.DEFAULT_GOOGLE_UPLOAD); + binding.editGoogleUpload.setEnabled(false); + } else { + binding.editGoogleUpload.setEnabled(true); + } + }); + + // If we default the folder, set the checkbox to checked and disable the edit field and set the default folder name + binding.butDefaultDownload.setOnClickListener(view -> { + if (binding.butDefaultDownload.isChecked()) { + binding.editGoogleDownload.setText(Constants.Settings.DEFAULT_GOOGLE_DOWNLOAD); + binding.editGoogleDownload.setEnabled(false); + } else { + binding.editGoogleDownload.setEnabled(true); + } + }); + } + + // ============================================================================================= + // Function: initRefresh + // Description: Initialize the Refresh button + // Parameters: void + // Output: void + // ============================================================================================= + private void initRefresh() { + binding.butRefresh.setOnClickListener(view -> { + if (Globals.network.hasActiveInternet()) { + binding.imageInternet.setVisibility(View.VISIBLE); + } else { + binding.imageInternet.setVisibility(View.INVISIBLE); + } + }); + } + + // ============================================================================================= + // Function: initChooseWifi + // Description: Initialize the ChooseWifi button + // Parameters: void + // Output: void + // ============================================================================================= + private void initChooseWifi() { + binding.butChoose.setOnClickListener(view -> Globals.network.pickWIFI()); + } + + // ============================================================================================= + // Function: updateWifiIcon + // Description: Update the Wi-Fi signal icon with the correct signal strength level + // Parameters: in_level signal strength level + // Output: void + // ============================================================================================= + private void updateWifiIcon(int in_level) { + // You would typically swap icons here based on level + // 0: No signal, 1-4: Signal bars + switch (in_level) { + case 4: binding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_4); break; + case 3: binding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_3); break; + case 2: binding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_2); break; + case 1: binding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_1); break; + default: binding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_0); break; + } + + // check if we have access to the internet + if (Globals.network.hasActiveInternet()) { + binding.imageInternet.setVisibility(View.VISIBLE); + } else { + binding.imageInternet.setVisibility(View.INVISIBLE); + } + } + + // ============================================================================================= + // Function: initNetwork + // Description: Initialize the network related fields and process + // Parameters: void + // Output: void + // ============================================================================================= + private void initNetwork() { + // setup Wi-Fi monitoring + connectivityManager = (ConnectivityManager) requireContext().getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkRequest networkRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + + networkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onCapabilitiesChanged(@NonNull Network in_network, @NonNull NetworkCapabilities in_capabilities) { + int rssi = 0; + + // On API 31+, WifiInfo is part of the capabilities (requires location permission) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + WifiInfo wifiInfo = (WifiInfo) in_capabilities.getTransportInfo(); + if (wifiInfo != null) rssi = wifiInfo.getRssi(); + } else { + // Fallback for API 30 + WifiManager wm = (WifiManager) requireContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE); + rssi = wm.getConnectionInfo().getRssi(); + } + + // Convert RSSI to a signal level (0 to 4) + int level = WifiManager.calculateSignalLevel(rssi, 5); + + // Update UI on the main thread + requireActivity().runOnUiThread(() -> updateWifiIcon(level)); + } + + @Override + public void onLost(@NonNull Network in_network) { + // Signal lost or Wi-Fi turned off + requireActivity().runOnUiThread(() -> updateWifiIcon(-1)); + } + }; + + connectivityManager.registerNetworkCallback(networkRequest, networkCallback); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPagerAdapter.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPagerAdapter.java index de1e85b7..02bb3913 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPagerAdapter.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPagerAdapter.java @@ -9,6 +9,7 @@ public class SettingsPagerAdapter extends FragmentStateAdapter { private SettingsPage1 fragmentPage1; private SettingsPage2 fragmentPage2; private SettingsPage3 fragmentPage3; + private SettingsPage4 fragmentPage4; public SettingsPagerAdapter(@NonNull FragmentActivity fragmentActivity) { super(fragmentActivity); @@ -31,14 +32,17 @@ public Fragment createFragment(int position) { fragmentPage3 = new SettingsPage3(); frag = fragmentPage3; break; - } + case 3: + fragmentPage4 = new SettingsPage4(); + frag = fragmentPage4; + break; } return frag; } @Override public int getItemCount() { - return 3; + return 4; } public SettingsPage1 getFragmentPage1() { @@ -50,4 +54,7 @@ public SettingsPage2 getFragmentPage2() { public SettingsPage3 getFragmentPage3() { return fragmentPage3; } + public SettingsPage4 getFragmentPage4() { + return fragmentPage4; + } } \ No newline at end of file diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index 5f0b929d..af5dd472 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -226,8 +226,8 @@ public Result sendFileToSQLServerBlocking() { return Result.HOST_UNREACHABLE; } - // String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; - String url = "jdbc:jtds:sqlserver://" + sql_server + ":1433/" + sql_database + ";loginTimeout=10;socketTimeout=30"; + String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; + String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; HashMap line_values = getFileAsStringHashMap(); @@ -238,7 +238,7 @@ public Result sendFileToSQLServerBlocking() { // On Android the driver must be registered explicitly; auto-discovery is unreliable try { - Class.forName("net.sourceforge.jtds.jdbc.Driver"); + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); } catch (ClassNotFoundException e) { return Result.SQL_EXCEPTION; } @@ -296,7 +296,6 @@ public Result sendFileToSQLServerBlockingJDBC() { } String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; - // String url = "jdbc:jtds:sqlserver://" + sql_server + ":1433/" + sql_database + ";loginTimeout=10;socketTimeout=30"; String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; HashMap line_values = new HashMap<>(); line_values = getFileAsStringHashMap(); @@ -454,7 +453,7 @@ public void uploadToGoogle(@NonNull Context in_context) { com.google.api.services.drive.model.File fileMetadata = new com.google.api.services.drive.model.File(); fileMetadata.setName(filename); - fileMetadata.setParents(Collections.singletonList(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE, ""))); + fileMetadata.setParents(Collections.singletonList(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE_UPLOAD, ""))); InputStream inputStream = in_context.getContentResolver().openInputStream(sourceUri); if (inputStream == null) { diff --git a/app/src/main/res/layout/fragment_settings_page1.xml b/app/src/main/res/layout/fragment_settings_page1.xml index d521521e..31d00ca5 100644 --- a/app/src/main/res/layout/fragment_settings_page1.xml +++ b/app/src/main/res/layout/fragment_settings_page1.xml @@ -12,6 +12,7 @@ android:layout_width="match_parent" android:layout_height="35dp" android:orientation="horizontal"> + + + + + + + + + + + - + + - + + + + + + + + + + + - + android:text="@string/settings_team_pref" + tools:ignore="RtlSymmetry" /> + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings_page2.xml b/app/src/main/res/layout/fragment_settings_page2.xml index 75a910bb..96b2d8cc 100644 --- a/app/src/main/res/layout/fragment_settings_page2.xml +++ b/app/src/main/res/layout/fragment_settings_page2.xml @@ -12,6 +12,7 @@ android:layout_width="match_parent" android:layout_height="35dp" android:orientation="horizontal"> + + + + - + + - - - - - - - - - - - - + tools:ignore="LabelFor" /> - + + + + diff --git a/app/src/main/res/layout/fragment_settings_page3.xml b/app/src/main/res/layout/fragment_settings_page3.xml index 5994ab59..8e0dabb0 100644 --- a/app/src/main/res/layout/fragment_settings_page3.xml +++ b/app/src/main/res/layout/fragment_settings_page3.xml @@ -64,34 +64,6 @@ app:cornerRadius="16dp"/> - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings_settings.xml b/app/src/main/res/values/strings_settings.xml index f14b2832..b7536509 100644 --- a/app/src/main/res/values/strings_settings.xml +++ b/app/src/main/res/values/strings_settings.xml @@ -13,7 +13,8 @@ Wi-Fi Connectivity Refresh Choose Wi-Fi - Google Drive ID + Google Upload Folder + Google Download Folder SQL Server Name SQL Database SQL User diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c5910cce..62c3f066 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,9 @@ [versions] -agp = "9.2.1" +agp = "9.3.1" junit = "4.13.2" junitVersion = "1.3.0" espressoCore = "3.7.0" -appcompat = "1.7.1" +appcompat = "1.8.0" material = "1.14.0" activity = "1.13.0" qrgenVersion = "4.3.0" @@ -13,7 +13,6 @@ google-api-client = "2.9.0" google-drive-v3 = "v3-rev20260405-2.0.0" play-services-auth = "21.6.0" documentfile = "1.1.0" -#jtds="1.3.1" mssql-jdbc="13.5.1.jre11-preview" [libraries] @@ -26,7 +25,6 @@ activity = { group = "androidx.activity", name = "activity", version.ref = "acti constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } preference = { group = "androidx.preference", name = "preference", version.ref = "preference" } qr-generator = { group = "com.journeyapps", name = "zxing-android-embedded", version.ref = "qrgenVersion" } -#jtds = { group = "net.sourceforge.jtds", name = "jtds", version.ref = "jtds"} documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" } google-api-client = { group = "com.google.api-client", name = "google-api-client-android", version.ref = "google-api-client" } google-drive-services = { group = "com.google.apis", name = "google-api-services-drive", version.ref = "google-drive-v3" } From ac3c24227cbe49dea5d67ed880459ea54fcb7980 Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Tue, 18 Aug 2026 10:49:34 -0700 Subject: [PATCH 09/13] add more visual confirmation of success/failure to transmit --- .../scouting_app/activities/SubmitData.java | 48 ++++++++++++------- .../scouting_app/utility/CPR_Network.java | 8 ++-- app/src/main/res/drawable/checkmark.xml | 20 ++++++++ app/src/main/res/drawable/x.xml | 20 ++++++++ app/src/main/res/layout/submit_data.xml | 26 ++++++++-- 5 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 app/src/main/res/drawable/checkmark.xml create mode 100644 app/src/main/res/drawable/x.xml diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 6943fff9..59426090 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -382,6 +382,8 @@ private void initMatch() { public void onItemSelected(AdapterView adapterView, View view, int i, long l) { // Save off what you selected to be used until changed again Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + submitDataBinding.imageGoogleResult.setImageResource(0); + submitDataBinding.imageDatabaseResult.setImageResource(0); } @Override @@ -505,28 +507,32 @@ private void initGoogle() { submitDataBinding.butSendGoogle.setOnClickListener(view -> { Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); + submitDataBinding.imageGoogleResult.setImageResource(0); // If the Drive service is already built this session, upload straight away if (Globals.network.isDriveServiceReady()) { - Globals.network.uploadToGoogle(this); - return; + if (Globals.network.uploadToGoogle(this)) { + submitDataBinding.imageGoogleResult.setImageResource(R.drawable.checkmark); + } else { + submitDataBinding.imageGoogleResult.setImageResource(R.drawable.x); + } } + }); - // Reuse an existing sign-in if it already granted the Drive scope - Scope driveScope = new Scope(CPR_Network.GOOGLE_DRIVE_SCOPE); - GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(this); - if (GoogleSignIn.hasPermissions(last, driveScope)) { - onGoogleSignedIn(last); - return; - } + // Reuse an existing sign-in if it already granted the Drive scope + Scope driveScope = new Scope(CPR_Network.GOOGLE_DRIVE_SCOPE); + GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(this); + if (GoogleSignIn.hasPermissions(last, driveScope)) { + onGoogleSignedIn(last); + return; + } - // Otherwise start the interactive sign-in / consent flow - GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestEmail() - .requestScopes(driveScope) - .build(); - googleSignInLauncher.launch(GoogleSignIn.getClient(this, gso).getSignInIntent()); - }); + // Otherwise start the interactive sign-in / consent flow + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestScopes(driveScope) + .build(); + googleSignInLauncher.launch(GoogleSignIn.getClient(this, gso).getSignInIntent()); } // ============================================================================================= @@ -546,6 +552,7 @@ private void initGoogleSignIn() { onGoogleSignedIn(account); } catch (ApiException e) { Toast.makeText(this, "Google sign-in failed", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageGoogleResult.setImageResource(R.drawable.x); } }); } @@ -559,6 +566,7 @@ private void initGoogleSignIn() { private void onGoogleSignedIn(GoogleSignInAccount in_account) { if (in_account == null || in_account.getAccount() == null) { Toast.makeText(this, "Google sign-in failed", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageGoogleResult.setImageResource(R.drawable.x); return; } @@ -585,6 +593,8 @@ private void initDatabase() { submitDataBinding.butSendDatabase.setEnabled(false); submitDataBinding.butSendDatabase.setClickable(false); submitDataBinding.butSendDatabase.setBackgroundColor(getColor(R.color.light_grey)); + submitDataBinding.imageDatabaseResult.setImageResource(0); + Globals.network.sendFileToSQLServer(result -> { submitDataBinding.butSendDatabase.setEnabled(true); @@ -593,22 +603,28 @@ private void initDatabase() { switch (result) { case TRANSMISSION_SUCCESS: Toast.makeText(this, "Successfully transmitted!", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageDatabaseResult.setImageResource(R.drawable.checkmark); break; case NO_NETWORK: Toast.makeText(this, "No network connection", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageDatabaseResult.setImageResource(R.drawable.x); break; case HOST_UNREACHABLE: Toast.makeText(this, "SQL Server is unreachable", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageDatabaseResult.setImageResource(R.drawable.x); break; case NO_DATA: Toast.makeText(this, "No data to send", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageDatabaseResult.setImageResource(R.drawable.x); break; case SQL_EXCEPTION: Toast.makeText(this, "SQL Server Exception", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageDatabaseResult.setImageResource(R.drawable.x); break; case TRANSMISSION_FAILURE: default: Toast.makeText(this, "Transmission failed", Toast.LENGTH_SHORT).show(); + submitDataBinding.imageDatabaseResult.setImageResource(R.drawable.x); break; } }); diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index af5dd472..740b7541 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -418,11 +418,11 @@ private void showToast(@NonNull Context in_context, @NonNull String in_message, // Parameters: in_context context used for content resolution and Toast feedback // Output: void // ============================================================================================= - public void uploadToGoogle(@NonNull Context in_context) { + public boolean uploadToGoogle(@NonNull Context in_context) { // We must have a Drive service (built from a signed-in account) before we can upload if (driveService == null) { showToast(in_context, "Google Upload Failed: Not signed in to Google", Toast.LENGTH_LONG); - return; + return false; } final String filename = Globals.CurrentCompetitionId + "_" + Globals.TransmitMatchNum + "_" + Globals.CurrentDeviceId + "_" + Globals.TransmitMatchType + ".csv"; @@ -431,7 +431,7 @@ public void uploadToGoogle(@NonNull Context in_context) { // validate the file exists if (df==null || !df.exists() || !df.isFile()) { showToast(in_context, "Google Upload Failed: File not found", Toast.LENGTH_LONG); - return; + return false; } final long localSize = df.length(); @@ -502,5 +502,7 @@ public void uploadToGoogle(@NonNull Context in_context) { showToast(in_context, "Google Upload Failed: Exception occurred", Toast.LENGTH_LONG); } }); + + return true; } } diff --git a/app/src/main/res/drawable/checkmark.xml b/app/src/main/res/drawable/checkmark.xml new file mode 100644 index 00000000..257a5ef1 --- /dev/null +++ b/app/src/main/res/drawable/checkmark.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/app/src/main/res/drawable/x.xml b/app/src/main/res/drawable/x.xml new file mode 100644 index 00000000..6afcac9d --- /dev/null +++ b/app/src/main/res/drawable/x.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/app/src/main/res/layout/submit_data.xml b/app/src/main/res/layout/submit_data.xml index 9dcc460d..3c8fe97d 100644 --- a/app/src/main/res/layout/submit_data.xml +++ b/app/src/main/res/layout/submit_data.xml @@ -146,10 +146,30 @@ + + + + + + + - - Date: Tue, 18 Aug 2026 10:55:36 -0700 Subject: [PATCH 10/13] removed 2025 image cleanup --- app/src/main/res/drawable/field2025.png | Bin 142978 -> 0 bytes app/src/main/res/layout/match.xml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 app/src/main/res/drawable/field2025.png diff --git a/app/src/main/res/drawable/field2025.png b/app/src/main/res/drawable/field2025.png deleted file mode 100644 index f634c9c94e80d959320bb5cf17921f0502bbb2b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142978 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 z 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 diff --git a/app/src/main/res/layout/match.xml b/app/src/main/res/layout/match.xml index 5e635a2b..6eb3d42f 100644 --- a/app/src/main/res/layout/match.xml +++ b/app/src/main/res/layout/match.xml @@ -164,7 +164,7 @@ android:layout_height="fill_parent" android:scaleType="fitXY" android:contentDescription="Shows the field of play" - app:srcCompat="@drawable/field2025" + app:srcCompat="@drawable/field2026" tools:ignore="HardcodedText,MissingConstraints" /> Date: Tue, 18 Aug 2026 15:21:04 -0700 Subject: [PATCH 11/13] removed unused function and fixed comment We're not using the extra function i had to use the JTBC driving when the SQL Server one had an error. Now that the SQL Server JDBC driver is fixed and working, we don't need this duplicate function. --- .../scouting_app/utility/CPR_Network.java | 64 +------------------ 1 file changed, 1 insertion(+), 63 deletions(-) diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index 740b7541..02c50af2 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -269,71 +269,9 @@ public Result sendFileToSQLServerBlocking() { } } - // ============================================================================================= - // Function: sendFileToSQLServerBlocking - // Description: Synchronous send. Must NOT be called on the main thread. - // Parameters: void - // Output: Result - // ============================================================================================= - @NonNull - public Result sendFileToSQLServerBlockingJDBC() { - if (!hasActiveInternet()) { - return Result.NO_NETWORK; - } - - String sql_server = Globals.sp.getString(Constants.Prefs.SQL_SERVER, ""); - String sql_database = Globals.sp.getString(Constants.Prefs.SQL_DATABASE, ""); - String sql_user = Globals.sp.getString(Constants.Prefs.SQL_USER, ""); - String sql_password = Globals.sp.getString(Constants.Prefs.SQL_PASSWORD, ""); - - // Before proceeding, make sure we have settings and a valid connection to the SQL Server - if (sql_server.isEmpty() || sql_database.isEmpty() || sql_user.isEmpty() || sql_password.isEmpty()) { - return Result.TRANSMISSION_FAILURE; - } - - if (!isHostReachable(sql_server, 1433, 3000)) { - return Result.HOST_UNREACHABLE; - } - - String url = "jdbc:sqlserver://" + sql_server + ";database=" + sql_database + ";encrypt=true;trustServerCertificate=true;useBulkCopyForBatchInsert=true;bulkCopyForBatchInsertFireTriggers=true"; - String sql = "INSERT INTO Load.Scouting_File(Line) VALUES(?)"; - HashMap line_values = new HashMap<>(); - line_values = getFileAsStringHashMap(); - - // Before proceeding, make sure we have data to send - if (line_values.isEmpty()) { - return Result.NO_DATA; - } - - try (Connection conn = DriverManager.getConnection(url, sql_user, sql_password)) { - conn.setAutoCommit(false); - // Insert the data, line by line - try (java.sql.PreparedStatement ps = conn.prepareStatement(sql)) { - for (String line : line_values.values()) { - ps.setString(1, line); - ps.addBatch(); - } - - ps.executeBatch(); - conn.commit(); - return Result.TRANSMISSION_SUCCESS; - } catch (SQLException e) { - // Rollback the transaction on error - try { - conn.rollback(); - } catch (SQLException ex) { - // ignore - } - return Result.SQL_EXCEPTION; - } - } catch (SQLException e) { - return Result.SQL_EXCEPTION; - } - } - // ============================================================================================= // Function: getFileAsStringHashMap - // Description: Initialize the Next Match button + // Description: Reads in the scouting file (defined by Globals) and convert it to a string hashmap // Parameters: void // Output: String representing the entire contents of the file // ============================================================================================= From 03cc859c91e8058e1958fa88691a1ef624056e7f Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Tue, 18 Aug 2026 15:47:33 -0700 Subject: [PATCH 12/13] use a callback for google results better use of a callback function to update the UI based on google's success - whether background tasks or foreground. --- .../scouting_app/activities/SubmitData.java | 56 +++++++++++++------ .../scouting_app/utility/CPR_Network.java | 21 +++++-- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 8672f761..56021ea2 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -561,31 +561,51 @@ private void initGoogle() { submitDataBinding.butSendGoogle.setOnClickListener(view -> { Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); submitDataBinding.imageGoogleResult.setImageResource(0); + submitDataBinding.butSendGoogle.setEnabled(false); + submitDataBinding.butSendGoogle.setClickable(false); + submitDataBinding.butSendGoogle.setBackgroundColor(getColor(R.color.light_grey)); + // If the Drive service is already built this session, upload straight away if (Globals.network.isDriveServiceReady()) { - if (Globals.network.uploadToGoogle(this)) { - submitDataBinding.imageGoogleResult.setImageResource(R.drawable.checkmark); - } else { - submitDataBinding.imageGoogleResult.setImageResource(R.drawable.x); - } + Globals.network.uploadToGoogle(this, this::handleGoogleUploadResult); + return; } + + // Reuse an existing sign-in if it already granted the Drive scope + Scope driveScope = new Scope(CPR_Network.GOOGLE_DRIVE_SCOPE); + GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(this); + if (GoogleSignIn.hasPermissions(last, driveScope)) { + onGoogleSignedIn(last); + return; + } + + // Otherwise start the interactive sign-in / consent flow + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestScopes(driveScope) + .build(); + googleSignInLauncher.launch(GoogleSignIn.getClient(this, gso).getSignInIntent()); }); + } - // Reuse an existing sign-in if it already granted the Drive scope - Scope driveScope = new Scope(CPR_Network.GOOGLE_DRIVE_SCOPE); - GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(this); - if (GoogleSignIn.hasPermissions(last, driveScope)) { - onGoogleSignedIn(last); - return; + // ============================================================================================= + // Function: handleGoogleUploadResult + // Description: Handle the result of a Google Drive upload + // Parameters: result the result of the upload + // Output: void + // ============================================================================================= + private void handleGoogleUploadResult(CPR_Network.Result result) { + if (result == CPR_Network.Result.TRANSMISSION_SUCCESS) { + submitDataBinding.imageGoogleResult.setImageResource(R.drawable.checkmark); + } else { + submitDataBinding.imageGoogleResult.setImageResource(R.drawable.x); } - // Otherwise start the interactive sign-in / consent flow - GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestEmail() - .requestScopes(driveScope) - .build(); - googleSignInLauncher.launch(GoogleSignIn.getClient(this, gso).getSignInIntent()); + submitDataBinding.butSendGoogle.setEnabled(true); + submitDataBinding.butSendGoogle.setClickable(true); + submitDataBinding.butSendGoogle.setBackgroundColor(getColor(R.color.white)); + } // ============================================================================================= @@ -624,7 +644,7 @@ private void onGoogleSignedIn(GoogleSignInAccount in_account) { } Globals.network.initDriveService(in_account.getAccount()); - Globals.network.uploadToGoogle(this); + Globals.network.uploadToGoogle(this, this::handleGoogleUploadResult); } // ============================================================================================= diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index 02c50af2..d3311acc 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -15,6 +15,7 @@ import androidx.annotation.NonNull; import androidx.documentfile.provider.DocumentFile; +import com.team3663.scouting_app.activities.SubmitData; import com.team3663.scouting_app.config.Constants; import com.team3663.scouting_app.config.Globals; @@ -24,6 +25,7 @@ import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.DriveScopes; +import com.team3663.scouting_app.databinding.SubmitDataBinding; import java.io.BufferedReader; import java.io.IOException; @@ -354,13 +356,15 @@ private void showToast(@NonNull Context in_context, @NonNull String in_message, // Description: Asynchronously copy the file to the shared Google Drive folder. initDriveService() // must have been called first. Feedback is shown via Toast on the main thread. // Parameters: in_context context used for content resolution and Toast feedback + // in_callback invoked on the main thread with the result // Output: void // ============================================================================================= - public boolean uploadToGoogle(@NonNull Context in_context) { + public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_callback) { // We must have a Drive service (built from a signed-in account) before we can upload if (driveService == null) { showToast(in_context, "Google Upload Failed: Not signed in to Google", Toast.LENGTH_LONG); - return false; + in_callback.onResult(Result.TRANSMISSION_FAILURE); + return; } final String filename = Globals.CurrentCompetitionId + "_" + Globals.TransmitMatchNum + "_" + Globals.CurrentDeviceId + "_" + Globals.TransmitMatchType + ".csv"; @@ -369,7 +373,8 @@ public boolean uploadToGoogle(@NonNull Context in_context) { // validate the file exists if (df==null || !df.exists() || !df.isFile()) { showToast(in_context, "Google Upload Failed: File not found", Toast.LENGTH_LONG); - return false; + in_callback.onResult(Result.NO_DATA); + return; } final long localSize = df.length(); @@ -380,12 +385,14 @@ public boolean uploadToGoogle(@NonNull Context in_context) { // validate connectivity if (!hasActiveInternet()) { showToast(in_context, "Google Upload Failed: No Internet Connection", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.NO_NETWORK)); return; } String mimeType = in_context.getContentResolver().getType(sourceUri); if (mimeType == null) { showToast(in_context, "Google Upload Failed: File Type Not Found", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } @@ -396,6 +403,7 @@ public boolean uploadToGoogle(@NonNull Context in_context) { InputStream inputStream = in_context.getContentResolver().openInputStream(sourceUri); if (inputStream == null) { showToast(in_context, "Google Upload Failed: Unable to open file", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } @@ -414,6 +422,7 @@ public boolean uploadToGoogle(@NonNull Context in_context) { if (uploadedFile == null) { showToast(in_context, "Google Upload Failed: Error transferring file", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } @@ -426,21 +435,23 @@ public boolean uploadToGoogle(@NonNull Context in_context) { if (remoteFile == null || remoteFile.getId() == null || Boolean.TRUE.equals(remoteFile.getTrashed())) { showToast(in_context, "Google Upload Failed: Unable to find remote file", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } if (remoteFile.getSize() == null || remoteFile.getSize() != localSize) { showToast(in_context, "Google Upload Failed: File size mismatch", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } showToast(in_context, "Google Upload Successful", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_SUCCESS)); } catch (Exception e) { showToast(in_context, "Google Upload Failed: Exception occurred", Toast.LENGTH_LONG); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); } }); - - return true; } } From 59f1bb04bebf363e14d810771eb1bc429e5860eb Mon Sep 17 00:00:00 2001 From: Jeff Stammler Date: Tue, 18 Aug 2026 23:23:34 -0700 Subject: [PATCH 13/13] added the download option added the ability to download newer files from google drive. made sure that settings sets the flag to load files even if "cancel" is used (if there were indeed files downloaded). Change applaunch to load ALL files, not just the match schedule. Fixed up visibility issue so that the loading of files again is shown on the screen. --- .../scouting_app/activities/AppLaunch.java | 19 +- .../scouting_app/activities/Settings.java | 25 +- .../scouting_app/activities/SubmitData.java | 10 +- .../scouting_app/fragments/SettingsPage1.java | 8 +- .../scouting_app/fragments/SettingsPage2.java | 2 +- .../scouting_app/fragments/SettingsPage4.java | 102 +++++++ .../scouting_app/utility/CPR_Network.java | 259 ++++++++++++++++-- .../res/layout/fragment_settings_page4.xml | 41 ++- app/src/main/res/values/strings_settings.xml | 1 + 9 files changed, 420 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/team3663/scouting_app/activities/AppLaunch.java b/app/src/main/java/com/team3663/scouting_app/activities/AppLaunch.java index dfca5d3c..8dcd1003 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/AppLaunch.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/AppLaunch.java @@ -52,9 +52,7 @@ public class AppLaunch extends AppCompatActivity { // There are no request codes Intent data = result.getData(); if (Objects.requireNonNull(data).getIntExtra(Constants.Settings.RELOAD_DATA_KEY, 0) == 1) { - Globals.MatchList.clearList(); - Globals.MatchList.LoadDataFile(appLaunchBinding.textStatusFile, appLaunchBinding.progressBarFile, appLaunchBinding.textPercentFile, appLaunchBinding.progressBarOverall, appLaunchBinding.textStatusOverall); - appLaunchBinding.textStatusFile.setText(""); + loadDataFiles(); } } }); @@ -259,6 +257,18 @@ private void initDataFiles() { // Output: void // ============================================================================================= private void loadDataFiles() { + // Ensure the loading file objects are visible + appLaunchBinding.progressBarOverall.setVisibility(View.VISIBLE); + appLaunchBinding.progressBarFile.setVisibility(View.VISIBLE); + appLaunchBinding.textStatusOverall.setVisibility(View.VISIBLE); + appLaunchBinding.textPercentOverall.setVisibility(View.VISIBLE); + appLaunchBinding.textStatusFile.setVisibility(View.VISIBLE); + appLaunchBinding.textPercentFile.setVisibility(View.VISIBLE); + appLaunchBinding.butStartScouting.setVisibility(View.INVISIBLE); + appLaunchBinding.imgButSettings.setVisibility(View.INVISIBLE); + appLaunchBinding.butStartScouting.setClickable(false); + appLaunchBinding.imgButSettings.setClickable(false); + // Clear out the lists, just in case _DataFile.clearAllLists(); @@ -291,6 +301,7 @@ public void run() { throw new RuntimeException(e); } + // Hide the loading file objects appLaunchBinding.progressBarOverall.setVisibility(View.INVISIBLE); appLaunchBinding.progressBarFile.setVisibility(View.INVISIBLE); appLaunchBinding.textStatusOverall.setVisibility(View.INVISIBLE); @@ -301,8 +312,6 @@ public void run() { appLaunchBinding.imgButSettings.setVisibility(View.VISIBLE); appLaunchBinding.butStartScouting.setClickable(true); appLaunchBinding.imgButSettings.setClickable(true); - appLaunchBinding.butStartScouting.setVisibility(View.VISIBLE); - appLaunchBinding.imgButSettings.setVisibility(View.VISIBLE); // Erase the status text appLaunchBinding.textStatusFile.setText(""); diff --git a/app/src/main/java/com/team3663/scouting_app/activities/Settings.java b/app/src/main/java/com/team3663/scouting_app/activities/Settings.java index 660a67c6..87828432 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/Settings.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/Settings.java @@ -11,13 +11,13 @@ import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; -import androidx.fragment.app.Fragment; import com.team3663.scouting_app.R; import com.team3663.scouting_app.config.*; import com.team3663.scouting_app.databinding.SettingsBinding; import com.team3663.scouting_app.fragments.*; import com.google.android.material.tabs.TabLayoutMediator; +import com.team3663.scouting_app.utility.CPR_Network; public class Settings extends AppCompatActivity { // ============================================================================================= @@ -43,6 +43,9 @@ protected void onCreate(Bundle in_savedInstanceState) { if (Globals.sp == null) Globals.sp = this.getSharedPreferences(getString(R.string.preference_setting_file_key), Context.MODE_PRIVATE); if (Globals.spe == null) Globals.spe = Globals.sp.edit(); + // Set the files downloaded to false when we first get into settings. + CPR_Network.filesDownloaded = false; + adapter = new SettingsPagerAdapter(this); settingsBinding.viewPager.setAdapter(adapter); @@ -54,12 +57,28 @@ protected void onCreate(Bundle in_savedInstanceState) { ).attach(); // Define a Cancel Button - settingsBinding.butCancel.setOnClickListener(view -> finish()); + settingsBinding.butCancel.setOnClickListener(view -> CancelSettings()); // Define a Save Button settingsBinding.butSave.setOnClickListener(view -> SaveSettings()); } + // ============================================================================================= + // Function: CancelSettings + // Description: Cancel any changes made (ignore them) but set the intent to reload the data + // if new files were downloaded. + // Parameters: void + // Output: void + // ============================================================================================= + private void CancelSettings() { + Intent intent = new Intent(); + + if (CPR_Network.filesDownloaded) intent.putExtra(Constants.Settings.RELOAD_DATA_KEY, 1); + + setResult(RESULT_OK, intent); + finish(); + } + // ============================================================================================= // Function: SaveSettings // Description: Save off the settings before closing this activity @@ -142,6 +161,8 @@ private void SaveSettings() { userField = fragmentPage4.binding.editGoogleDownload.getText(); Globals.spe.putString(Constants.Prefs.GOOGLE_DRIVE_DOWNLOAD, (userField != null) ? userField.toString() : ""); + + if (CPR_Network.filesDownloaded) intent.putExtra(Constants.Settings.RELOAD_DATA_KEY, 1); } Globals.spe.apply(); diff --git a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java index 56021ea2..b21ae616 100644 --- a/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java +++ b/app/src/main/java/com/team3663/scouting_app/activities/SubmitData.java @@ -271,9 +271,7 @@ private class AchievementTimerTaskEnd extends TimerTask { @Override public void run() { - SubmitData.this.runOnUiThread(() -> { - animateAchievementEnd(); - }); + SubmitData.this.runOnUiThread(SubmitData.this::animateAchievementEnd); if (isLast) closeAchievements(); } @@ -538,7 +536,6 @@ private void initBluetooth() { Globals.isPractice = false; Globals.TransmitMatchNum = Integer.parseInt(submitDataBinding.spinnerMatch.getSelectedItem().toString()); - // Intent GoToBluetooth = new Intent(SubmitData.this, Bluetooth.class); // startActivity(GoToBluetooth); @@ -568,7 +565,7 @@ private void initGoogle() { // If the Drive service is already built this session, upload straight away if (Globals.network.isDriveServiceReady()) { - Globals.network.uploadToGoogle(this, this::handleGoogleUploadResult); + Globals.network.uploadToGoogle(this::handleGoogleUploadResult); return; } @@ -605,7 +602,6 @@ private void handleGoogleUploadResult(CPR_Network.Result result) { submitDataBinding.butSendGoogle.setEnabled(true); submitDataBinding.butSendGoogle.setClickable(true); submitDataBinding.butSendGoogle.setBackgroundColor(getColor(R.color.white)); - } // ============================================================================================= @@ -644,7 +640,7 @@ private void onGoogleSignedIn(GoogleSignInAccount in_account) { } Globals.network.initDriveService(in_account.getAccount()); - Globals.network.uploadToGoogle(this, this::handleGoogleUploadResult); + Globals.network.uploadToGoogle(this::handleGoogleUploadResult); } // ============================================================================================= diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java index 6bebc319..aea86ace 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage1.java @@ -15,6 +15,8 @@ import com.team3663.scouting_app.config.Globals; import com.team3663.scouting_app.databinding.FragmentSettingsPage1Binding; +import java.util.Objects; + public class SettingsPage1 extends Fragment { public FragmentSettingsPage1Binding binding; public int savedCompetitionId; @@ -44,7 +46,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat // ============================================================================================= private void initCompetition() { // Adds Competition information to spinner - ArrayAdapter adp_Competition = new ArrayAdapter<>(requireContext(), + ArrayAdapter adp_Competition = new ArrayAdapter<>(requireContext().getApplicationContext(), R.layout.cpr_spinner, Globals.CompetitionList.getCompetitionList()); adp_Competition.setDropDownViewResource(R.layout.cpr_spinner_item); binding.spinnerCompetition.setAdapter(adp_Competition); @@ -75,7 +77,7 @@ public void onNothingSelected(AdapterView parent) {} // ============================================================================================= private void initDevice() { // Adds Device information to spinner - ArrayAdapter adp_Device = new ArrayAdapter<>(requireContext(), + ArrayAdapter adp_Device = new ArrayAdapter<>(requireContext().getApplicationContext(), R.layout.cpr_spinner, Globals.DeviceList.getDeviceList()); adp_Device.setDropDownViewResource(R.layout.cpr_spinner_item); binding.spinnerDevice.setAdapter(adp_Device); @@ -155,7 +157,7 @@ private void initFieldOrientation() { // ============================================================================================= private void initPrefTeamPos() { // Adds PreferredTeamPosition information to spinner - ArrayAdapter adp_PrefTeamPos = new ArrayAdapter<>(requireContext(), + ArrayAdapter adp_PrefTeamPos = new ArrayAdapter<>(requireContext().getApplicationContext(), R.layout.cpr_spinner, Constants.Settings.PREF_TEAM_POS); adp_PrefTeamPos.setDropDownViewResource(R.layout.cpr_spinner_item); binding.spinnerPrefTeamPos.setAdapter(adp_PrefTeamPos); diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java index 071af679..9c44e853 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage2.java @@ -42,7 +42,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat // ============================================================================================= private void initColors() { // Adds Color information to spinner - ArrayAdapter adp_Color = new ArrayAdapter<>(requireContext(), + ArrayAdapter adp_Color = new ArrayAdapter<>(requireContext().getApplicationContext(), R.layout.cpr_spinner, Globals.ColorList.getDescriptionList()); adp_Color.setDropDownViewResource(R.layout.cpr_spinner_item); binding.spinnerColor.setAdapter(adp_Color); diff --git a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java index 010e4852..3a7640d0 100644 --- a/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java +++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage4.java @@ -1,6 +1,7 @@ package com.team3663.scouting_app.fragments; import android.content.Context; +import android.content.Intent; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; @@ -12,19 +13,33 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.Scope; import com.team3663.scouting_app.R; import com.team3663.scouting_app.config.Constants; import com.team3663.scouting_app.config.Globals; import com.team3663.scouting_app.databinding.FragmentSettingsPage4Binding; +import com.team3663.scouting_app.utility.CPR_Network; + +import java.util.Objects; public class SettingsPage4 extends Fragment { public FragmentSettingsPage4Binding binding; private ConnectivityManager connectivityManager; private ConnectivityManager.NetworkCallback networkCallback; + private ActivityResultLauncher googleSignInLauncher; + @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -37,6 +52,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat super.onViewCreated(view, savedInstanceState); initNetwork(); initChooseWifi(); + initGoogleSignIn(); initRefresh(); initFields(); } @@ -50,6 +66,46 @@ public void onDestroyView() { } } + // ============================================================================================= + // Function: handleGoogleDownloadResult + // Description: Handle the result of a Google Drive download + // Parameters: result the result of the download + // Output: void + // ============================================================================================= + private void handleGoogleDownloadResult(CPR_Network.Result result) { + if (result == CPR_Network.Result.TRANSMISSION_SUCCESS) { + binding.imageGoogleResult.setImageResource(R.drawable.checkmark); + } else { + binding.imageGoogleResult.setImageResource(R.drawable.x); + } + + binding.butDownload.setEnabled(true); + binding.butDownload.setClickable(true); + binding.butDownload.setBackgroundColor(requireContext().getColor(R.color.white)); + } + + // ============================================================================================= + // Function: initGoogleSignIn + // Description: Register the launcher that receives the result of the Google sign-in flow. + // Parameters: void + // Output: void + // ============================================================================================= + private void initGoogleSignIn() { + googleSignInLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + try { + GoogleSignInAccount account = GoogleSignIn + .getSignedInAccountFromIntent(result.getData()) + .getResult(ApiException.class); + onGoogleSignedIn(account); + } catch (ApiException e) { + Toast.makeText(requireContext().getApplicationContext(), "Google sign-in failed", Toast.LENGTH_SHORT).show(); + binding.imageGoogleResult.setImageResource(R.drawable.x); + } + }); + } + // ============================================================================================= // Function: initFields // Description: Initialize the Fields on the fragment @@ -101,6 +157,52 @@ private void initFields() { binding.editGoogleDownload.setEnabled(true); } }); + + // Listen for a button click + binding.butDownload.setOnClickListener(view -> { + binding.butDownload.setEnabled(false); + binding.butDownload.setClickable(false); + binding.butDownload.setBackgroundColor(requireContext().getColor(R.color.light_grey)); + + // If the Drive service is already built this session, upload straight away + if (Globals.network.isDriveServiceReady()) { + Globals.network.downloadFromGoogle(this::handleGoogleDownloadResult); + return; + } + + // Reuse an existing sign-in if it already granted the Drive scope + Scope driveScope = new Scope(CPR_Network.GOOGLE_DRIVE_SCOPE); + GoogleSignInAccount last = GoogleSignIn.getLastSignedInAccount(requireContext().getApplicationContext()); + if (GoogleSignIn.hasPermissions(last, driveScope)) { + onGoogleSignedIn(last); + return; + } + + // Otherwise start the interactive sign-in / consent flow + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestScopes(driveScope) + .build(); + googleSignInLauncher.launch(GoogleSignIn.getClient(requireContext().getApplicationContext(), gso).getSignInIntent()); + + }); + } + + // ============================================================================================= + // Function: onGoogleSignedIn + // Description: Build the Drive service from the signed-in account and start the upload. + // Parameters: in_account the account returned from Google sign-in + // Output: void + // ============================================================================================= + private void onGoogleSignedIn(GoogleSignInAccount in_account) { + if (in_account == null || in_account.getAccount() == null) { + Toast.makeText(requireContext().getApplicationContext(), "Google sign-in failed", Toast.LENGTH_SHORT).show(); + binding.imageGoogleResult.setImageResource(R.drawable.x); + return; + } + + Globals.network.initDriveService(in_account.getAccount()); + Globals.network.downloadFromGoogle(this::handleGoogleDownloadResult); } // ============================================================================================= diff --git a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java index d3311acc..d2ec823c 100644 --- a/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java +++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java @@ -15,7 +15,8 @@ import androidx.annotation.NonNull; import androidx.documentfile.provider.DocumentFile; -import com.team3663.scouting_app.activities.SubmitData; +import com.google.api.services.drive.model.File; +import com.google.api.services.drive.model.FileList; import com.team3663.scouting_app.config.Constants; import com.team3663.scouting_app.config.Globals; @@ -25,19 +26,24 @@ import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.DriveScopes; -import com.team3663.scouting_app.databinding.SubmitDataBinding; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -46,6 +52,8 @@ // Description: Custom class to handle network related tasks. // ============================================================================================= public class CPR_Network { + public static boolean filesDownloaded = false; + // ============================================================================================= // Class Globals // ============================================================================================= @@ -57,7 +65,7 @@ public class CPR_Network { // files this app creates, which is all we do here: create a file in the shared folder (any // signed-in account can write to it via the folder's "anyone with the link can edit" grant). // Note: this scope does NOT allow listing/reading other files in that folder. - public static final String GOOGLE_DRIVE_SCOPE = DriveScopes.DRIVE_FILE; + public static final String GOOGLE_DRIVE_SCOPE = DriveScopes.DRIVE; private Drive driveService; // ============================================================================================= @@ -70,6 +78,7 @@ public enum Result { TRANSMISSION_SUCCESS, // data sent successfully TRANSMISSION_FAILURE, // data send failed NO_DATA, // no data to send + LOCAL_DIR_DNE, // no local directory exists SQL_EXCEPTION // SQL error occurred } @@ -347,22 +356,21 @@ public boolean isDriveServiceReady() { // in_duration Toast.LENGTH_SHORT or Toast.LENGTH_LONG // Output: void // ============================================================================================= - private void showToast(@NonNull Context in_context, @NonNull String in_message, int in_duration) { - mainHandler.post(() -> Toast.makeText(in_context, in_message, in_duration).show()); + private void showToast(@NonNull Context in_context, @NonNull String in_message) { + mainHandler.post(() -> Toast.makeText(in_context, in_message, Toast.LENGTH_LONG).show()); } // ============================================================================================= // Function: uploadToGoogle // Description: Asynchronously copy the file to the shared Google Drive folder. initDriveService() // must have been called first. Feedback is shown via Toast on the main thread. - // Parameters: in_context context used for content resolution and Toast feedback - // in_callback invoked on the main thread with the result + // Parameters: in_callback invoked on the main thread with the result // Output: void // ============================================================================================= - public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_callback) { + public void uploadToGoogle(@NonNull Callback in_callback) { // We must have a Drive service (built from a signed-in account) before we can upload if (driveService == null) { - showToast(in_context, "Google Upload Failed: Not signed in to Google", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: Not signed in to Google"); in_callback.onResult(Result.TRANSMISSION_FAILURE); return; } @@ -372,7 +380,7 @@ public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_cal // validate the file exists if (df==null || !df.exists() || !df.isFile()) { - showToast(in_context, "Google Upload Failed: File not found", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: File not found"); in_callback.onResult(Result.NO_DATA); return; } @@ -384,14 +392,14 @@ public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_cal try { // validate connectivity if (!hasActiveInternet()) { - showToast(in_context, "Google Upload Failed: No Internet Connection", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: No Internet Connection"); mainHandler.post(() -> in_callback.onResult(Result.NO_NETWORK)); return; } - String mimeType = in_context.getContentResolver().getType(sourceUri); + String mimeType = appContext.getContentResolver().getType(sourceUri); if (mimeType == null) { - showToast(in_context, "Google Upload Failed: File Type Not Found", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: File Type Not Found"); mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } @@ -400,9 +408,9 @@ public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_cal fileMetadata.setName(filename); fileMetadata.setParents(Collections.singletonList(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE_UPLOAD, ""))); - InputStream inputStream = in_context.getContentResolver().openInputStream(sourceUri); + InputStream inputStream = appContext.getContentResolver().openInputStream(sourceUri); if (inputStream == null) { - showToast(in_context, "Google Upload Failed: Unable to open file", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: Unable to open file"); mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } @@ -421,7 +429,7 @@ public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_cal .execute(); if (uploadedFile == null) { - showToast(in_context, "Google Upload Failed: Error transferring file", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: Error transferring file"); mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } @@ -434,24 +442,235 @@ public void uploadToGoogle(@NonNull Context in_context, @NonNull Callback in_cal .execute(); if (remoteFile == null || remoteFile.getId() == null || Boolean.TRUE.equals(remoteFile.getTrashed())) { - showToast(in_context, "Google Upload Failed: Unable to find remote file", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: Unable to find remote file"); mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } if (remoteFile.getSize() == null || remoteFile.getSize() != localSize) { - showToast(in_context, "Google Upload Failed: File size mismatch", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Failed: File size mismatch"); mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); return; } - showToast(in_context, "Google Upload Successful", Toast.LENGTH_LONG); + showToast(appContext, "Google Upload Successful"); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_SUCCESS)); + } + catch (Exception e) { + showToast(appContext, "Google Upload Failed: Exception occurred"); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); + } + }); + } + + // ============================================================================================= + // Function: downloadFromGoogle + // Description: Asynchronously copy the files from the shared Google Drive folder. initDriveService() + // must have been called first. Feedback is shown via Toast on the main thread. + // For each remote file: + // - if no local copy exists, download it + // - if a local copy exists and the MD5 checksum matches, skip it + // - if a local copy exists but the MD5 checksum differs, re-download (overwrite) + // Parameters: in_callback invoked on the main thread with the result + // Output: void + // ============================================================================================= + public void downloadFromGoogle(@NonNull Callback in_callback) { + // validate connectivity + if (!hasActiveInternet()) { + showToast(appContext, "Google Download Failed: No Internet Connection"); + mainHandler.post(() -> in_callback.onResult(Result.NO_NETWORK)); + return; + } + + // We must have a Drive service (built from a signed-in account) before we can upload + if (driveService == null) { + showToast(appContext, "Google Download Failed: Not signed in to Google"); + in_callback.onResult(Result.TRANSMISSION_FAILURE); + return; + } + + // Ensure the folder exists + if (!Globals.input_df.exists()) { + showToast(appContext, "Google Download Failed: Local directory not found"); + in_callback.onResult(Result.LOCAL_DIR_DNE); + return; + } + + final String filename = Globals.CurrentCompetitionId + "_" + Globals.TransmitMatchNum + "_" + Globals.CurrentDeviceId + "_" + Globals.TransmitMatchType + ".csv"; + DocumentFile df = Globals.output_df.findFile(filename); + + executor.execute(() -> { + try { + int files_downloaded = 0; + for (File remote : listGoogleFiles()) { + // silently ignore any google native docs (they don't have a checksum) + if (remote.getMd5Checksum() == null) continue; + + String name = remote.getName(); + DocumentFile local = Globals.input_df.findFile(name); + + // if the local file exists but isn't a file, abort + if (local != null && !local.isFile()) { + showToast(appContext, "Google Download Failed: File not found"); + mainHandler.post(() -> in_callback.onResult(Result.NO_DATA)); + return; + } + + // if the local file doesn't exist, download it. + if (local == null || !local.exists()) { + if (downloadOneFileFromGoogle(remote.getId(), name)) files_downloaded++; + else { + showToast(appContext, "Google Download Failed: Error transmitting file " + name); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_SUCCESS)); + } + continue; + } + + String remoteMD5 = remote.getMd5Checksum(); + String localMD5 = getFileMD5(local); + + // if the checksums differ, download it again + if (!remoteMD5.equalsIgnoreCase(localMD5)) { + if (downloadOneFileFromGoogle(remote.getId(), name)) files_downloaded++; + else { + showToast(appContext, "Google Download Failed: Error transmitting file " + local.getName()); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_SUCCESS)); + } + } + } + + if (files_downloaded > 0) { + showToast(appContext, "Google Download Successful: " + files_downloaded + " files"); + CPR_Network.filesDownloaded = true; + } + else showToast(appContext, "Google Download: No new files found"); + mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_SUCCESS)); } catch (Exception e) { - showToast(in_context, "Google Upload Failed: Exception occurred", Toast.LENGTH_LONG); + if (!Objects.equals(e.getMessage(), "No files found")) showToast(appContext, "Google Download Failed: Exception occurred"); mainHandler.post(() -> in_callback.onResult(Result.TRANSMISSION_FAILURE)); } }); } + + // ============================================================================================= + // Function: downloadOneFileFromGoogle + // Description: download a single file from Google + // Parameters: in_remoteFileId file ID from Google Drive + // in_df local documentFile + // Output: List of Files + // ============================================================================================= + public boolean downloadOneFileFromGoogle(String in_remoteFileId, String in_localFileName) throws IOException { + DocumentFile tmp = Globals.input_df.findFile(in_localFileName + ".part"); + DocumentFile dest = Globals.input_df.findFile(in_localFileName); + + // if the tmp file exists, delete it + if (tmp != null && tmp.exists()) tmp.delete(); + + // create the file + tmp = Globals.input_df.createFile("text/csv", in_localFileName + ".part"); + + if (tmp == null) return false; + + try (OutputStream out = appContext.getContentResolver().openOutputStream(tmp.getUri(), "wt")) { + if (out == null) return false; + + driveService.files().get(in_remoteFileId).executeMediaAndDownloadTo(out); + out.flush(); + } catch (IOException e) { + tmp.delete(); + return false; + } + + // if we fail to delete the local file, abort + if (dest != null && dest.exists() && !dest.delete()) { + tmp.delete(); + return false; + } + + // if we fail to rename the tmp file, abort + if (!tmp.renameTo(in_localFileName)) { + tmp.delete(); + return false; + } + + return true; + } + + // ============================================================================================= + // Function: listGoogleFiles + // Description: Lists all non-trashed files directly inside a GoogleDrive folder + // Parameters: void + // Output: List of Files + // ============================================================================================= + public List listGoogleFiles() throws IOException { + List files = new ArrayList<>(); + String pageToken = null; + String query = "'" + Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE_DOWNLOAD, "") + "' in parents and trashed = false " + + "and mimeType != 'application/vnd.google-apps.folder'"; + do { + FileList page = driveService.files().list() + .setQ(query) + .setSpaces("drive") + .setFields("nextPageToken, files(id, name, md5Checksum, mimeType, size)") + .setSupportsAllDrives(true) + .setIncludeItemsFromAllDrives(true) + .setPageSize(1000) + .setPageToken(pageToken) + .execute(); + + if (page.getFiles() != null) { + files.addAll(page.getFiles()); + } + + pageToken = page.getNextPageToken(); + } while (pageToken != null); + + if (files.isEmpty()) { + showToast(appContext, "Google Download Failed: No files found"); + throw new IOException("No files found"); + } + + return files; + } + + // ============================================================================================= + // Function: getFileMD5 + // Description: Calculates the MD5 hash of a file. This matches the md5Checksum provided by + // Google Drive metadata. + // Parameters: in_df DocumentFile to hash + // Output: String representing the hex MD5 hash, or null if it fails + // ============================================================================================= + public String getFileMD5(DocumentFile in_df) { + // validate the file exists + if (in_df==null || !in_df.exists() || !in_df.isFile()) { + showToast(appContext, "Local Checksum (MD5) Failed: File not found"); + return ""; + } + + try (InputStream is = appContext.getContentResolver().openInputStream(in_df.getUri())) { + MessageDigest digest = MessageDigest.getInstance("MD5"); + if (is == null) return null; + byte[] buffer = new byte[8192]; + int read; + while ((read = is.read(buffer)) > 0) { + digest.update(buffer, 0, read); + } + byte[] md5sum = digest.digest(); + StringBuilder hexString = new StringBuilder(); + for (byte b : md5sum) { + hexString.append(Character.forDigit((b >> 4) & 0xF, 16)); + hexString.append(Character.forDigit(b & 0xF, 16)); + } + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + showToast(appContext, "Local Checksum (MD5) Failed: MD5 algorithm unavailable"); + return null; + } + catch (IOException e) { + showToast(appContext, "Local Checksum (MD5) Failed: Unable to read file"); + return null; + } + } } diff --git a/app/src/main/res/layout/fragment_settings_page4.xml b/app/src/main/res/layout/fragment_settings_page4.xml index d8f9fd5a..135d4dae 100644 --- a/app/src/main/res/layout/fragment_settings_page4.xml +++ b/app/src/main/res/layout/fragment_settings_page4.xml @@ -97,7 +97,7 @@ - + + android:orientation="horizontal"> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings_settings.xml b/app/src/main/res/values/strings_settings.xml index b7536509..3f98c4ce 100644 --- a/app/src/main/res/values/strings_settings.xml +++ b/app/src/main/res/values/strings_settings.xml @@ -15,6 +15,7 @@ Choose Wi-Fi Google Upload Folder Google Download Folder + Download Files SQL Server Name SQL Database SQL User