+
+
+
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 72a1dab5..271cb7de 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
@@ -30,6 +30,7 @@
import com.team3663.scouting_app.config.Constants;
import com.team3663.scouting_app.config.Globals;
import com.team3663.scouting_app.databinding.AppLaunchBinding;
+import com.team3663.scouting_app.utility.CPR_Network;
import com.team3663.scouting_app.utility.dataFile.*;
import java.util.List;
@@ -128,6 +129,8 @@ protected void onCreate(Bundle in_savedInstanceState) {
// While loading Matches, we messed with Globals.CurrentMatchType, so reset it
Globals.CurrentMatchType = Constants.PreMatch.DEFAULT_MATCH_TYPE;
+ Globals.network = new CPR_Network(this);
+ boolean b = Globals.network.hasActiveInternet();
}
// =============================================================================================
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 1f01cd8f..f6c5242b 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
@@ -377,6 +377,7 @@ private void initQuit() {
.setPositiveButton(getString(R.string.submit_alert_quit_positive), (dialog, which) -> {
SubmitData.this.finishAffinity();
stopLockTask();
+ Globals.network.shutdown();
System.exit(0);
})
diff --git a/app/src/main/java/com/team3663/scouting_app/config/Globals.java b/app/src/main/java/com/team3663/scouting_app/config/Globals.java
index 25e321fe..d2ca9be7 100644
--- a/app/src/main/java/com/team3663/scouting_app/config/Globals.java
+++ b/app/src/main/java/com/team3663/scouting_app/config/Globals.java
@@ -9,6 +9,7 @@
import com.team3663.scouting_app.data.Accuracy;
import com.team3663.scouting_app.data.ClimbLevel;
import com.team3663.scouting_app.data.ClimbPosition;
+import com.team3663.scouting_app.utility.CPR_Network;
import com.team3663.scouting_app.utility.Logger;
import com.team3663.scouting_app.utility.achievements.Achievements;
import com.team3663.scouting_app.utility.dataFile.*;
@@ -73,4 +74,6 @@ public class Globals {
public static int TransmitMatchNum;
public static String TransmitMatchType;
+
+ public static CPR_Network network;
}
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
new file mode 100644
index 00000000..d92b97db
--- /dev/null
+++ b/app/src/main/java/com/team3663/scouting_app/utility/CPR_Network.java
@@ -0,0 +1,146 @@
+package com.team3663.scouting_app.utility;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Checks whether a remote host:port is reachable.
+ *
+ * Two-step check:
+ *
+ * - Is there any active network with internet capability? (cheap, no I/O)
+ * - Can we open a TCP socket to the given host:port? (blocking, runs off the UI thread)
+ *
+ *
+ * Required manifest permissions:
+ *
+ * <uses-permission android:name="android.permission.INTERNET" />
+ * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ *
+ */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
+ }
+
+ /**
+ * Delivered on the main thread.
+ */
+ public interface Callback {
+ void onResult(@NonNull Result result);
+ }
+
+ private final Context appContext;
+ private final ExecutorService executor;
+ private final Handler mainHandler;
+
+ public CPR_Network(@NonNull Context context) {
+ // Use the application context to avoid leaking an Activity.
+ this.appContext = context.getApplicationContext();
+ this.executor = Executors.newCachedThreadPool();
+ this.mainHandler = new Handler(Looper.getMainLooper());
+ }
+
+ /**
+ * Asynchronously checks reachability. The callback is invoked on the main thread.
+ *
+ * @param host hostname or IP of the remote machine
+ * @param port port the remote service listens on (e.g. 8080, 443, 22)
+ * @param timeoutMs socket connect timeout in milliseconds
+ * @param callback invoked on the main thread with the result
+ */
+ public void check(@NonNull String host, int port, int timeoutMs, @NonNull Callback callback) {
+ executor.execute(() -> {
+ Result result = checkBlocking(host, port, timeoutMs);
+ mainHandler.post(() -> callback.onResult(result));
+ });
+ }
+
+ /**
+ * Synchronous check. Must NOT be called on the main thread (blocks on socket I/O).
+ * Exposed for use inside your own background threads / coroutines.
+ */
+ @NonNull
+ public Result checkBlocking(@NonNull String host, int port, int timeoutMs) {
+ if (!hasActiveInternet()) {
+ return Result.NO_NETWORK;
+ }
+ return isHostReachable(host, port, timeoutMs)
+ ? Result.REACHABLE
+ : Result.HOST_UNREACHABLE;
+ }
+
+ /**
+ * Step 1: is there an active, internet-capable network?
+ */
+ public boolean hasActiveInternet() {
+ ConnectivityManager cm =
+ (ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm == null) {
+ return false;
+ }
+ Network network = cm.getActiveNetwork();
+ if (network == null) {
+ return false;
+ }
+ NetworkCapabilities caps = cm.getNetworkCapabilities(network);
+ return caps != null
+ && caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ }
+
+ /**
+ * Step 2: can we open a TCP connection to host:port?
+ */
+ private boolean isHostReachable(@NonNull String host, int port, int timeoutMs) {
+ try (Socket socket = new Socket()) {
+ socket.connect(new InetSocketAddress(host, port), timeoutMs);
+ return true;
+ } catch (IOException e) {
+ // unreachable, connection refused, or timed out
+ return false;
+ }
+ }
+
+ /**
+ * Call when you're done (e.g. in onDestroy) to release the thread pool.
+ */
+ public void shutdown() {
+ executor.shutdownNow();
+ }
+
+ /**
+ * Choose new wifi to connect to
+ */
+ public void pickWIFI() {
+ try {
+ // Try quick Wi-Fi panel
+ Intent GoToSystemWIFI = new Intent(Settings.Panel.ACTION_WIFI);
+ GoToSystemWIFI.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ appContext.startActivity(GoToSystemWIFI);
+ } catch (Exception e) {
+ // Fallback to full Wi-Fi settings
+ Intent GoToSystemWIFI = new Intent(Settings.ACTION_WIFI_SETTINGS);
+ GoToSystemWIFI.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ appContext.startActivity(GoToSystemWIFI);
+ }
+ }
+}
From efa8641c5d48e8037ebcc027749836155ac503f2 Mon Sep 17 00:00:00 2001
From: Jeff Stammler
Date: Wed, 1 Jul 2026 18:40:26 -0700
Subject: [PATCH 2/6] almost there
---
.../scouting_app/activities/SubmitData.java | 101 ++++++-
app/src/main/res/drawable/internet.xml | 20 ++
app/src/main/res/drawable/wifi_bar_0.xml | 20 ++
app/src/main/res/drawable/wifi_bar_1.xml | 10 +
app/src/main/res/drawable/wifi_bar_2.xml | 10 +
app/src/main/res/drawable/wifi_bar_3.xml | 20 ++
app/src/main/res/drawable/wifi_bar_4.xml | 20 ++
app/src/main/res/layout/submit_data.xml | 255 ++++++++++--------
app/src/main/res/values/strings_submit.xml | 3 +
9 files changed, 353 insertions(+), 106 deletions(-)
create mode 100644 app/src/main/res/drawable/internet.xml
create mode 100644 app/src/main/res/drawable/wifi_bar_0.xml
create mode 100644 app/src/main/res/drawable/wifi_bar_1.xml
create mode 100644 app/src/main/res/drawable/wifi_bar_2.xml
create mode 100644 app/src/main/res/drawable/wifi_bar_3.xml
create mode 100644 app/src/main/res/drawable/wifi_bar_4.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 f6c5242b..17a322bb 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
@@ -2,13 +2,22 @@
import android.annotation.SuppressLint;
import android.app.AlertDialog;
+import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
+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.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import androidx.activity.EdgeToEdge;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
@@ -35,6 +44,8 @@ public class SubmitData extends AppCompatActivity {
private SubmitDataBinding submitDataBinding;
private static final Timer achievement_timer = new Timer();
private static MediaPlayer media;
+ private ConnectivityManager connectivityManager;
+ private ConnectivityManager.NetworkCallback networkCallback;
@SuppressLint({"SetTextI18n", "MissingInflatedId"})
@Override
@@ -61,6 +72,7 @@ protected void onCreate(Bundle in_savedInstanceState) {
}
// Initialize activity components that don't log anything
+ initNetwork();
initMatchType();
initMatch();
initQR();
@@ -70,6 +82,15 @@ protected void onCreate(Bundle in_savedInstanceState) {
initOverride();
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ // Important: Unregister to avoid memory leaks
+ if (connectivityManager != null && networkCallback != null) {
+ connectivityManager.unregisterNetworkCallback(networkCallback);
+ }
+ }
+
// =============================================================================================
// Function: initMatchType
// Description: Initialize the Match Type field
@@ -258,6 +279,35 @@ private void closeAchievements() {
media.release();
}
+ // =============================================================================================
+ // 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: submitDataBinding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_4); break;
+ case 3: submitDataBinding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_3); break;
+ case 2: submitDataBinding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_2); break;
+ case 1: submitDataBinding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_1); break;
+ default: submitDataBinding.imageWifiSignal.setImageResource(R.drawable.wifi_bar_0); break;
+ }
+
+ // check if we have access to the internet
+ if (Globals.network.hasActiveInternet()) {
+ submitDataBinding.imageInternet.setVisibility(View.VISIBLE);
+ submitDataBinding.butSendGoogle.setEnabled(true);
+ submitDataBinding.butSendDatabase.setEnabled(true);
+ } else {
+ submitDataBinding.imageInternet.setVisibility(View.INVISIBLE);
+ submitDataBinding.butSendGoogle.setEnabled(false);
+ submitDataBinding.butSendDatabase.setEnabled(false);
+ }
+ }
+
// =============================================================================================
// Function: initOverride
// Description: Override team number reset for next match
@@ -320,6 +370,52 @@ private void initMatch() {
if (adp_Match.getCount() > 0) submitDataBinding.spinnerMatch.setSelection(adp_Match.getCount() - 1, true);
}
+ // =============================================================================================
+ // Function: initNetwork
+ // Description: Initialize the network related fields and process
+ // Parameters: void
+ // Output: void
+ // =============================================================================================
+ private void initNetwork() {
+ // setup Wi-Fi monitoring
+ connectivityManager = (ConnectivityManager) 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) 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
+ runOnUiThread(() -> updateWifiIcon(level));
+ }
+
+ @Override
+ public void onLost(@NonNull Network in_network) {
+ // Signal lost or Wi-Fi turned off
+ runOnUiThread(() -> updateWifiIcon(-1));
+ }
+ };
+
+ connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
+ }
+
// =============================================================================================
// Function: initQR
// Description: Initialize the QR Code field
@@ -347,6 +443,9 @@ private void initQR() {
// Output: void
// =============================================================================================
private void initBluetooth() {
+ // Until we have BT working...
+ submitDataBinding.butSendBT.setEnabled(false);
+
submitDataBinding.butSendBT.setOnClickListener(view -> {
// Reset pre-Match settings for next time
Globals.numStartingGamePiece = Constants.PreMatch.STARTING_GAME_PIECES;
@@ -404,7 +503,7 @@ private void initNext() {
Globals.affectedByDefenseValue = Constants.PostMatch.AFFECTED_BY_DEFENSE_NOT_SELECTED;
Globals.isPractice = false;
- // Increases the team number so that it auto fills for the next match correctly
+ // Increases the team number so that it will autofill for the next match correctly
Globals.CurrentMatchNumber++;
Intent GoToPreMatch = new Intent(SubmitData.this, PreMatch.class);
diff --git a/app/src/main/res/drawable/internet.xml b/app/src/main/res/drawable/internet.xml
new file mode 100644
index 00000000..c0408de6
--- /dev/null
+++ b/app/src/main/res/drawable/internet.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/wifi_bar_0.xml b/app/src/main/res/drawable/wifi_bar_0.xml
new file mode 100644
index 00000000..a3ceb954
--- /dev/null
+++ b/app/src/main/res/drawable/wifi_bar_0.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/wifi_bar_1.xml b/app/src/main/res/drawable/wifi_bar_1.xml
new file mode 100644
index 00000000..d1c28f74
--- /dev/null
+++ b/app/src/main/res/drawable/wifi_bar_1.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/wifi_bar_2.xml b/app/src/main/res/drawable/wifi_bar_2.xml
new file mode 100644
index 00000000..1bf8f255
--- /dev/null
+++ b/app/src/main/res/drawable/wifi_bar_2.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/wifi_bar_3.xml b/app/src/main/res/drawable/wifi_bar_3.xml
new file mode 100644
index 00000000..0b53c28a
--- /dev/null
+++ b/app/src/main/res/drawable/wifi_bar_3.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/wifi_bar_4.xml b/app/src/main/res/drawable/wifi_bar_4.xml
new file mode 100644
index 00000000..6354f09d
--- /dev/null
+++ b/app/src/main/res/drawable/wifi_bar_4.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 880ad340..9dcc460d 100644
--- a/app/src/main/res/layout/submit_data.xml
+++ b/app/src/main/res/layout/submit_data.xml
@@ -8,113 +8,149 @@
android:background="@color/cpr_bkgnd"
tools:context=".activities.SubmitData">
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal">
+
+
+
+
+
+
-
-
+ android:layout_height="match_parent"
+ android:layout_weight="1.5"
+ android:layout_marginTop="40dp"
+ android:orientation="vertical">
-
-
-
-
-
+
+
+
+
+
diff --git a/app/src/main/res/values/strings_submit.xml b/app/src/main/res/values/strings_submit.xml
index 8a6089a3..ac65efd3 100644
--- a/app/src/main/res/values/strings_submit.xml
+++ b/app/src/main/res/values/strings_submit.xml
@@ -6,4 +6,7 @@
Quit app
Are you sure you want to Quit the app?
Quit
+ Wi-Fi signal strength
+ Internet access
+ Match Type:
From 35cba602bdfe899db1ea759cbcf223f8e0cf16a7 Mon Sep 17 00:00:00 2001
From: Jeff Stammler
Date: Fri, 3 Jul 2026 00:43:39 -0700
Subject: [PATCH 3/6] settings layout and applaunch addition
---
.../scouting_app/activities/AppLaunch.java | 16 +-
.../scouting_app/fragments/SettingsPage3.java | 37 +++
.../fragments/SettingsPagerAdapter.java | 11 +-
app/src/main/res/layout/app_launch.xml | 10 +
.../res/layout/fragment_settings_page3.xml | 219 ++++++++++++++++++
app/src/main/res/values/strings_settings.xml | 9 +
6 files changed, 296 insertions(+), 6 deletions(-)
create mode 100644 app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage3.java
create mode 100644 app/src/main/res/layout/fragment_settings_page3.xml
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 271cb7de..dfca5d3c 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
@@ -93,6 +93,10 @@ protected void onCreate(Bundle in_savedInstanceState) {
return insets;
});
+ // Default to NO internet
+ appLaunchBinding.imageInternet.setVisibility(View.INVISIBLE);
+ Globals.network = new CPR_Network(this);
+
// Display app version
PackageInfo pInfo;
try {
@@ -119,7 +123,7 @@ protected void onCreate(Bundle in_savedInstanceState) {
boolean havePerms = !perm_list.isEmpty();
// If we have storage permissions go ahead and load the data.
- // Otherwise, initiate getting permissions (which will then load the data afterwards)
+ // Otherwise, initiate getting permissions (which will then load the data afterward)
if (havePerms) {
Globals.baseStorageURI = Uri.parse(Globals.sp.getString(Constants.Prefs.STORAGE_URI, null));
initDataFiles();
@@ -129,9 +133,13 @@ protected void onCreate(Bundle in_savedInstanceState) {
// While loading Matches, we messed with Globals.CurrentMatchType, so reset it
Globals.CurrentMatchType = Constants.PreMatch.DEFAULT_MATCH_TYPE;
- Globals.network = new CPR_Network(this);
- boolean b = Globals.network.hasActiveInternet();
- }
+
+ // check if we have access to the internet
+ if (Globals.network.hasActiveInternet())
+ appLaunchBinding.imageInternet.setVisibility(View.VISIBLE);
+ else
+ appLaunchBinding.imageInternet.setVisibility(View.INVISIBLE);
+ }
// =============================================================================================
// Function: initSettings
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
new file mode 100644
index 00000000..0c5e4ca3
--- /dev/null
+++ b/app/src/main/java/com/team3663/scouting_app/fragments/SettingsPage3.java
@@ -0,0 +1,37 @@
+package com.team3663.scouting_app.fragments;
+
+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.databinding.FragmentSettingsPage3Binding;
+
+public class SettingsPage3 extends Fragment {
+ public FragmentSettingsPage3Binding binding;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FragmentSettingsPage3Binding.inflate(inflater, container, false);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ initColors();
+ }
+
+ // =============================================================================================
+ // Function: initColors
+ // Description: Initialize the Color Palette field
+ // Parameters: void
+ // Output: void
+ // =============================================================================================
+ private void initColors() {
+ }
+}
\ 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 645527f4..de1e85b7 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
@@ -8,6 +8,7 @@
public class SettingsPagerAdapter extends FragmentStateAdapter {
private SettingsPage1 fragmentPage1;
private SettingsPage2 fragmentPage2;
+ private SettingsPage3 fragmentPage3;
public SettingsPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
@@ -26,6 +27,10 @@ public Fragment createFragment(int position) {
fragmentPage2 = new SettingsPage2();
frag = fragmentPage2;
break;
+ case 2:
+ fragmentPage3 = new SettingsPage3();
+ frag = fragmentPage3;
+ break;
}
return frag;
@@ -33,14 +38,16 @@ public Fragment createFragment(int position) {
@Override
public int getItemCount() {
- return 2;
+ return 3;
}
public SettingsPage1 getFragmentPage1() {
return fragmentPage1;
}
-
public SettingsPage2 getFragmentPage2() {
return fragmentPage2;
}
+ public SettingsPage3 getFragmentPage3() {
+ return fragmentPage3;
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_launch.xml b/app/src/main/res/layout/app_launch.xml
index 3fad18cb..d9106f6f 100644
--- a/app/src/main/res/layout/app_launch.xml
+++ b/app/src/main/res/layout/app_launch.xml
@@ -20,6 +20,16 @@
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="MissingConstraints,VisualLintOverlap" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 7440e2eb..f14b2832 100644
--- a/app/src/main/res/values/strings_settings.xml
+++ b/app/src/main/res/values/strings_settings.xml
@@ -10,4 +10,13 @@
Field orientation:
Shadow Mode:
QR Code Size:
+ Wi-Fi Connectivity
+ Refresh
+ Choose Wi-Fi
+ Google Drive ID
+ SQL Server Name
+ SQL Database
+ SQL User
+ SQL Password
+
From d2f9c2fdd34e94c1f01891fde15349a42dca68dc Mon Sep 17 00:00:00 2001
From: Jeff Stammler
Date: Sun, 5 Jul 2026 23:39:04 -0700
Subject: [PATCH 4/6] added network info into settings.
---
.../scouting_app/activities/Settings.java | 30 +++-
.../scouting_app/config/Constants.java | 5 +
.../scouting_app/fragments/SettingsPage3.java | 140 +++++++++++++++++-
3 files changed, 166 insertions(+), 9 deletions(-)
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 7b191d5a..71e0d8c2 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
@@ -4,6 +4,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.text.Editable;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
@@ -14,9 +15,7 @@
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.SettingsPagerAdapter;
-import com.team3663.scouting_app.fragments.SettingsPage1;
-import com.team3663.scouting_app.fragments.SettingsPage2;
+import com.team3663.scouting_app.fragments.*;
import com.google.android.material.tabs.TabLayoutMediator;
public class Settings extends AppCompatActivity {
@@ -70,8 +69,9 @@ private void SaveSettings() {
Intent intent = new Intent();
SettingsPage1 fragmentPage1 = adapter.getFragmentPage1();
SettingsPage2 fragmentPage2 = adapter.getFragmentPage2();
+ SettingsPage3 fragmentPage3 = adapter.getFragmentPage3();
- // Page1 & Page2 Settings
+ // Page1 Settings
if (fragmentPage1 != null && fragmentPage1.binding != null) {
int CompetitionId = Globals.CompetitionList.getCompetitionId(fragmentPage1.binding.spinnerCompetition.getSelectedItem().toString());
@@ -97,7 +97,7 @@ private void SaveSettings() {
Globals.spe.putInt(Constants.Prefs.NUM_MATCHES, NumMatches);
}
- // UI Settings
+ // Page2 Settings
if (fragmentPage2 != null && fragmentPage2.binding != null) {
int ColorId = Globals.ColorList.getColorId(fragmentPage2.binding.spinnerColor.getSelectedItem().toString());
if (ColorId > 0) {
@@ -114,6 +114,26 @@ private void SaveSettings() {
Globals.spe.putInt(Constants.Prefs.PREF_ORIENTATION, Globals.CurrentFieldOrientationPos);
}
+ // 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() : "");
+
+ userField = fragmentPage3.binding.editDatabase.getText();
+ Globals.spe.putString(Constants.Prefs.SQL_DATABASE, (userField != null) ? userField.toString() : "");
+
+ userField = fragmentPage3.binding.editUser.getText();
+ Globals.spe.putString(Constants.Prefs.SQL_USER, (userField != null) ? userField.toString() : "");
+
+ userField = fragmentPage3.binding.editPassword.getText();
+ Globals.spe.putString(Constants.Prefs.SQL_PASSWORD, (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 52bb622b..9b689a85 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,6 +121,11 @@ 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 SQL_SERVER = "PreferredSqlServer";
+ public static final String SQL_DATABASE = "PreferredSqlDatabase";
+ public static final String SQL_USER = "PreferredSqlUser";
+ public static final String SQL_PASSWORD = "PreferredSqlPassword";
}
public static class Settings {
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 0c5e4ca3..801224f1 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
@@ -1,5 +1,14 @@
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;
+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;
@@ -8,10 +17,17 @@
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
+import com.team3663.scouting_app.R;
+import com.team3663.scouting_app.activities.QRCode;
+import com.team3663.scouting_app.activities.SubmitData;
+import com.team3663.scouting_app.config.Constants;
+import com.team3663.scouting_app.config.Globals;
import com.team3663.scouting_app.databinding.FragmentSettingsPage3Binding;
public class SettingsPage3 extends Fragment {
public FragmentSettingsPage3Binding binding;
+ private ConnectivityManager connectivityManager;
+ private ConnectivityManager.NetworkCallback networkCallback;
@Nullable
@Override
@@ -23,15 +39,131 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- initColors();
+ 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() {
+ binding.editGoogleDrive.setText(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE, ""));
+ binding.editServer.setText(Globals.sp.getString(Constants.Prefs.SQL_SERVER, ""));
+ binding.editDatabase.setText(Globals.sp.getString(Constants.Prefs.SQL_DATABASE, ""));
+ binding.editUser.setText(Globals.sp.getString(Constants.Prefs.SQL_USER, ""));
+ binding.editPassword.setText(Globals.sp.getString(Constants.Prefs.SQL_PASSWORD, ""));
+ }
+
+ // =============================================================================================
+ // 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
// =============================================================================================
- // Function: initColors
- // Description: Initialize the Color Palette field
+ 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 initColors() {
+ 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
From feeb7a6d84e41d3d9b27bff5dbb6092615b51170 Mon Sep 17 00:00:00 2001
From: Jeff Stammler
Date: Mon, 6 Jul 2026 12:04:56 -0700
Subject: [PATCH 5/6] fixed comment blocks and coding standards
---
.../scouting_app/fragments/SettingsPage3.java | 8 +-
.../scouting_app/utility/CPR_Network.java | 126 ++++++++++--------
2 files changed, 69 insertions(+), 65 deletions(-)
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 801224f1..1b2a7ade 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
@@ -1,7 +1,6 @@
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;
@@ -18,8 +17,6 @@
import androidx.fragment.app.Fragment;
import com.team3663.scouting_app.R;
-import com.team3663.scouting_app.activities.QRCode;
-import com.team3663.scouting_app.activities.SubmitData;
import com.team3663.scouting_app.config.Constants;
import com.team3663.scouting_app.config.Globals;
import com.team3663.scouting_app.databinding.FragmentSettingsPage3Binding;
@@ -29,7 +26,6 @@ public class SettingsPage3 extends Fragment {
private ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback networkCallback;
- @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentSettingsPage3Binding.inflate(inflater, container, false);
@@ -91,9 +87,7 @@ private void initRefresh() {
// Output: void
// =============================================================================================
private void initChooseWifi() {
- binding.butChoose.setOnClickListener(view -> {
- Globals.network.pickWIFI();
- });
+ binding.butChoose.setOnClickListener(view -> Globals.network.pickWIFI());
}
// =============================================================================================
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 d92b97db..e42c8f61 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
@@ -17,81 +17,80 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-/**
- * Checks whether a remote host:port is reachable.
- *
- * Two-step check:
- *
- * - Is there any active network with internet capability? (cheap, no I/O)
- * - Can we open a TCP socket to the given host:port? (blocking, runs off the UI thread)
- *
- *
- * Required manifest permissions:
- *
- * <uses-permission android:name="android.permission.INTERNET" />
- * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- *
- */public class CPR_Network {
+// =============================================================================================
+// Class: CPR_Network
+// Description: Custom class to handle network related tasks.
+// =============================================================================================
+public class CPR_Network {
+ // =============================================================================================
+ // Class Globals
+ // =============================================================================================
+ private final Context appContext;
+ private final ExecutorService executor;
+ private final Handler mainHandler;
- /**
- * Why a reachability check ended the way it did.
- */
+ // =============================================================================================
+ // 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
}
- /**
- * Delivered on the main thread.
- */
public interface Callback {
void onResult(@NonNull Result result);
}
- private final Context appContext;
- private final ExecutorService executor;
- private final Handler mainHandler;
-
- public CPR_Network(@NonNull Context context) {
+ // Constructor: create the new Network object
+ public CPR_Network(@NonNull Context in_context) {
// Use the application context to avoid leaking an Activity.
- this.appContext = context.getApplicationContext();
+ this.appContext = in_context.getApplicationContext();
this.executor = Executors.newCachedThreadPool();
this.mainHandler = new Handler(Looper.getMainLooper());
}
- /**
- * Asynchronously checks reachability. The callback is invoked on the main thread.
- *
- * @param host hostname or IP of the remote machine
- * @param port port the remote service listens on (e.g. 8080, 443, 22)
- * @param timeoutMs socket connect timeout in milliseconds
- * @param callback invoked on the main thread with the result
- */
- public void check(@NonNull String host, int port, int timeoutMs, @NonNull Callback callback) {
+ // =============================================================================================
+ // Function: check (step 1)
+ // Description: Asynchronously checks reachability. The callback is invoked on the main thread.
+ // 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 check(@NonNull String in_host, int in_port, int in_timeoutMs, @NonNull Callback in_callback) {
executor.execute(() -> {
- Result result = checkBlocking(host, port, timeoutMs);
- mainHandler.post(() -> callback.onResult(result));
+ Result result = checkBlocking(in_host, in_port, in_timeoutMs);
+ mainHandler.post(() -> in_callback.onResult(result));
});
}
- /**
- * Synchronous check. Must NOT be called on the main thread (blocks on socket I/O).
- * Exposed for use inside your own background threads / coroutines.
- */
+ // =============================================================================================
+ // Function: checkBlocking
+ // Description: Synchronous check. Must NOT be called on the main thread (blocks on socket I/O).
+ // Exposed for use inside your own background threads / coroutines.
+ // 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
+ // Output: void
+ // =============================================================================================
@NonNull
- public Result checkBlocking(@NonNull String host, int port, int timeoutMs) {
+ public Result checkBlocking(@NonNull String in_host, int in_port, int in_timeoutMs) {
if (!hasActiveInternet()) {
return Result.NO_NETWORK;
}
- return isHostReachable(host, port, timeoutMs)
+ return isHostReachable(in_host, in_port, in_timeoutMs)
? Result.REACHABLE
: Result.HOST_UNREACHABLE;
}
- /**
- * Step 1: is there an active, internet-capable network?
- */
+ // =============================================================================================
+ // Function: hasActiveInternet
+ // Description: is there an active, internet-capable network?
+ // Parameters: void
+ // Output: void
+ // =============================================================================================
public boolean hasActiveInternet() {
ConnectivityManager cm =
(ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -107,12 +106,17 @@ public boolean hasActiveInternet() {
&& caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
- /**
- * Step 2: can we open a TCP connection to host:port?
- */
- private boolean isHostReachable(@NonNull String host, int port, int timeoutMs) {
+ // =============================================================================================
+ // Function: isHostReachable (step 2)
+ // Description: can we open a TCP connection to host:port?
+ // 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
+ // Output: void
+ // =============================================================================================
+ private boolean isHostReachable(@NonNull String in_host, int in_port, int in_timeoutMs) {
try (Socket socket = new Socket()) {
- socket.connect(new InetSocketAddress(host, port), timeoutMs);
+ socket.connect(new InetSocketAddress(in_host, in_port), in_timeoutMs);
return true;
} catch (IOException e) {
// unreachable, connection refused, or timed out
@@ -120,16 +124,22 @@ private boolean isHostReachable(@NonNull String host, int port, int timeoutMs) {
}
}
- /**
- * Call when you're done (e.g. in onDestroy) to release the thread pool.
- */
+ // =============================================================================================
+ // Function: shutdown
+ // Description: Call when you're done (e.g. in onDestroy) to release the thread pool.
+ // Parameters: void
+ // Output: void
+ // =============================================================================================
public void shutdown() {
executor.shutdownNow();
}
- /**
- * Choose new wifi to connect to
- */
+ // =============================================================================================
+ // Function: pickWIFI
+ // Description: Choose new wifi to connect to
+ // Parameters: void
+ // Output: void
+ // =============================================================================================
public void pickWIFI() {
try {
// Try quick Wi-Fi panel
From b03620da0952604591b9a59fdcb5b4fd7a0d1c8c Mon Sep 17 00:00:00 2001
From: Jeff Stammler
Date: Mon, 6 Jul 2026 14:18:11 -0700
Subject: [PATCH 6/6] added defaults for network fields
---
.../team3663/scouting_app/fragments/SettingsPage3.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
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 1b2a7ade..db706230 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,11 +57,11 @@ public void onDestroyView() {
// Output: void
// =============================================================================================
private void initFields() {
- binding.editGoogleDrive.setText(Globals.sp.getString(Constants.Prefs.GOOGLE_DRIVE, ""));
- binding.editServer.setText(Globals.sp.getString(Constants.Prefs.SQL_SERVER, ""));
- binding.editDatabase.setText(Globals.sp.getString(Constants.Prefs.SQL_DATABASE, ""));
- binding.editUser.setText(Globals.sp.getString(Constants.Prefs.SQL_USER, ""));
- binding.editPassword.setText(Globals.sp.getString(Constants.Prefs.SQL_PASSWORD, ""));
+ 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"));
+ binding.editPassword.setText(Globals.sp.getString(Constants.Prefs.SQL_PASSWORD, "Aa98o1nTlHb4sg2u0YB2eNHxVfU4n17z"));
}
// =============================================================================================