cleaning up UI

This commit is contained in:
2025-04-15 12:36:18 -04:00
parent 89cda0d210
commit 2e4d02b503
11 changed files with 495 additions and 94 deletions

View File

@@ -1,18 +1,32 @@
# SimpleFileUpload
Android client written in java to easily upload Samsung dumpstate files.
Android client written in Java to easily upload files, including Samsung dumpstate files.
Note - this requires that you leverage SimpleFileUpload-Server
## Features
- Upload Samsung dumpstate files or any file via UI or share intent
- General file upload capability from device storage
- Support for Samsung dumpstate files as a specialized feature
- Automatic dumpstate file detection
- Automatically compress files to .zip format before upload
- Modern Material Design interface
- View upload history with received codes
- Copy codes for easy sharing
- Support for Android 14+ with proper foreground service implementation
- MVC architecture for clean code separation
## Recent Updates
- Redesigned UI with improved user experience
- Added general file upload capability as the main feature
- Dumpstate upload functionality moved to a sub-feature
- Updated app icons for a more modern look
- Fixed broadcast receiver registration for Android 13+
- Added proper foreground service type declaration for Android 14+
- Improved reliability of upload completion handling
- Enhanced error handling and logging
## Upcoming Features
- Multiple file upload support
- Progress tracking for large files
- Dark mode support
- Upload history filtering and search
- QR code generation for quick sharing

View File

@@ -11,7 +11,7 @@
<application
android:allowBackup="true"
android:icon="@android:drawable/ic_menu_upload"
android:icon="@drawable/ic_app_icon"
android:label="SimpleLogUpload"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"

View File

@@ -173,7 +173,7 @@ public class FileUploadForegroundService extends Service {
notificationBuilder = new NotificationCompat.Builder(this, AppConstants.NOTIFICATION_CHANNEL_ID)
.setContentTitle("File Upload")
.setContentText("Preparing file...")
.setSmallIcon(R.drawable.logupload)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.setProgress(100, 0, true)
.setOngoing(true);

View File

@@ -1,6 +1,9 @@
package com.mattintech.simplelogupload.view;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.content.BroadcastReceiver;
@@ -36,15 +39,24 @@ import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = AppConstants.APP_TAG + "MainActivity";
private TextView resultView;
private Button uploadButton;
private TextView dumpstateStatusText;
private TextView selectedFileText;
private Button selectFileButton;
private Button uploadDumpstateButton;
private Button uploadSelectedFileButton;
private ProgressBar progressBar;
private CardView selectedFileCard;
private File selectedFile;
private File dumpstateFile;
private UploadController uploadController;
// BroadcastReceiver to listen for upload results
private BroadcastReceiver uploadReceiver;
// Activity result launcher for file picking
private ActivityResultLauncher<String> filePickerLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -59,17 +71,33 @@ public class MainActivity extends AppCompatActivity {
return;
}
// Set content view
setContentView(R.layout.activity_main);
uploadController = new UploadController(this);
// Initialize UI elements
resultView = findViewById(R.id.resultView);
uploadButton = findViewById(R.id.uploadButton);
dumpstateStatusText = findViewById(R.id.dumpstateStatusText);
selectedFileText = findViewById(R.id.selectedFileText);
selectFileButton = findViewById(R.id.selectFileButton);
uploadDumpstateButton = findViewById(R.id.uploadDumpstateButton);
uploadSelectedFileButton = findViewById(R.id.uploadSelectedFileButton);
progressBar = findViewById(R.id.progressBar);
selectedFileCard = findViewById(R.id.selectedFileCard);
// Set up button click listeners
uploadButton.setOnClickListener(v -> startUpload());
selectFileButton.setOnClickListener(v -> openFilePicker());
uploadDumpstateButton.setOnClickListener(v -> uploadDumpstate());
uploadSelectedFileButton.setOnClickListener(v -> uploadSelectedFile());
// Initialize file picker launcher
filePickerLauncher = registerForActivityResult(
new ActivityResultContracts.GetContent(),
uri -> {
if (uri != null) {
handleFileSelection(uri);
}
});
// Check for necessary permissions
checkAndRequestPermissions();
@@ -120,19 +148,14 @@ public class MainActivity extends AppCompatActivity {
// For now, just handle the first URI
Uri sharedUri = sharedUris.get(0);
resultView.setText("Processing shared file...");
progressBar.setVisibility(View.VISIBLE);
uploadButton.setEnabled(false);
// Process the shared URI
ShareIntentHandler.processSharedUri(this, sharedUri)
.thenAccept(file -> {
// Save the file for upload
selectedFile = file;
updateSelectedFile(file);
runOnUiThread(() -> {
resultView.setText("File ready: " + file.getName());
uploadButton.setEnabled(true);
uploadButton.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
});
})
@@ -140,15 +163,113 @@ public class MainActivity extends AppCompatActivity {
Log.e(TAG, "Error processing shared file", ex);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this,
"Error processing file: " + ex.getMessage(),
getString(R.string.file_error, ex.getMessage()),
Toast.LENGTH_LONG).show();
resultView.setText("Error processing file");
progressBar.setVisibility(View.GONE);
});
return null;
});
}
/**
* Opens the file picker
*/
private void openFilePicker() {
filePickerLauncher.launch("*/*");
}
/**
* Handle file selection from file picker
*
* @param uri The URI of the selected file
*/
private void handleFileSelection(Uri uri) {
progressBar.setVisibility(View.VISIBLE);
// Process the URI
ShareIntentHandler.processSharedUri(this, uri)
.thenAccept(file -> {
// Save the file for upload
updateSelectedFile(file);
runOnUiThread(() -> {
progressBar.setVisibility(View.GONE);
});
})
.exceptionally(ex -> {
Log.e(TAG, "Error processing selected file", ex);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this,
getString(R.string.file_error, ex.getMessage()),
Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.GONE);
});
return null;
});
}
/**
* Upload the selected file
*/
private void uploadSelectedFile() {
if (selectedFile == null || !selectedFile.exists()) {
Toast.makeText(this, R.string.no_file_selected, Toast.LENGTH_SHORT).show();
return;
}
// Update UI
progressBar.setVisibility(View.VISIBLE);
uploadSelectedFileButton.setEnabled(false);
selectedFileText.setText(getString(R.string.uploading_file, selectedFile.getName()));
// Start the upload service
startUploadService(selectedFile);
}
/**
* Upload the dumpstate file
*/
private void uploadDumpstate() {
if (dumpstateFile == null || !dumpstateFile.exists()) {
Toast.makeText(this, R.string.no_dumpstate_found, Toast.LENGTH_SHORT).show();
return;
}
// Update UI
progressBar.setVisibility(View.VISIBLE);
uploadDumpstateButton.setEnabled(false);
dumpstateStatusText.setText(getString(R.string.uploading_file, dumpstateFile.getName()));
// Start the upload service
startUploadService(dumpstateFile);
}
/**
* Start the upload service with the given file
*
* @param file The file to upload
*/
private void startUploadService(File file) {
// Start the upload service
Intent serviceIntent = new Intent(this, FileUploadForegroundService.class);
serviceIntent.putExtra(FileUploadForegroundService.EXTRA_FILE_PATH, file.getAbsolutePath());
startService(serviceIntent);
}
/**
* Update the selected file UI
*
* @param file The selected file
*/
private void updateSelectedFile(File file) {
selectedFile = file;
runOnUiThread(() -> {
selectedFileCard.setVisibility(View.VISIBLE);
selectedFileText.setText(getString(R.string.selected_file, file.getName()));
uploadSelectedFileButton.setVisibility(View.VISIBLE);
uploadSelectedFileButton.setEnabled(true);
});
}
/**
* Set up the broadcast receiver for upload results
*/
@@ -158,7 +279,8 @@ public class MainActivity extends AppCompatActivity {
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received broadcast: " + intent.getAction());
progressBar.setVisibility(View.GONE);
uploadButton.setEnabled(true);
uploadSelectedFileButton.setEnabled(true);
uploadDumpstateButton.setEnabled(true);
if (intent.getAction().equals(AppConstants.ACTION_UPLOAD_COMPLETE)) {
String uploadCode = intent.getStringExtra(AppConstants.EXTRA_UPLOAD_CODE);
@@ -167,13 +289,27 @@ public class MainActivity extends AppCompatActivity {
} else if (intent.getAction().equals(AppConstants.ACTION_UPLOAD_ERROR)) {
String errorMessage = intent.getStringExtra(AppConstants.EXTRA_UPLOAD_ERROR);
Log.e(TAG, "Upload error: " + errorMessage);
Toast.makeText(MainActivity.this, "Upload Error: " + errorMessage, Toast.LENGTH_LONG).show();
resultView.setText("Upload failed: " + errorMessage);
Toast.makeText(MainActivity.this,
getString(R.string.upload_error, errorMessage),
Toast.LENGTH_LONG).show();
resetUI();
}
}
};
}
/**
* Reset the UI after upload completion or error
*/
private void resetUI() {
dumpstateStatusText.setText(dumpstateFile != null ?
getString(R.string.dumpstate_found, dumpstateFile.getName()) :
getString(R.string.no_dumpstate_found));
if (selectedFile != null) {
selectedFileText.setText(getString(R.string.selected_file, selectedFile.getName()));
}
}
@Override
protected void onResume() {
super.onResume();
@@ -231,23 +367,17 @@ public class MainActivity extends AppCompatActivity {
* Check for dumpstate files and update the UI
*/
private void checkForDumpStateAndUpdateUI() {
// If we already have a selected file (e.g., from share), use that
if (selectedFile != null && selectedFile.exists()) {
resultView.setText("File selected: " + selectedFile.getName());
uploadButton.setVisibility(View.VISIBLE);
return;
}
// Otherwise, look for dumpstate files
// Look for dumpstate files
File mostRecentDumpStateFile = FileController.getMostRecentDumpStateFile();
if (mostRecentDumpStateFile != null) {
selectedFile = mostRecentDumpStateFile;
resultView.setText("Dumpstate found: " + mostRecentDumpStateFile.getName());
uploadButton.setVisibility(View.VISIBLE);
dumpstateFile = mostRecentDumpStateFile;
dumpstateStatusText.setText(getString(R.string.dumpstate_found, mostRecentDumpStateFile.getName()));
uploadDumpstateButton.setEnabled(true);
} else {
resultView.setText("No dumpstate file found.");
uploadButton.setVisibility(View.GONE);
dumpstateFile = null;
dumpstateStatusText.setText(R.string.no_dumpstate_found);
uploadDumpstateButton.setEnabled(false);
}
}
@@ -259,31 +389,11 @@ public class MainActivity extends AppCompatActivity {
if (PermissionUtil.hasAllFilesAccessPermission()) {
checkForDumpStateAndUpdateUI();
} else {
Toast.makeText(this, "Storage permission not granted!", Toast.LENGTH_SHORT).show();
Toast.makeText(this, R.string.permission_not_granted, Toast.LENGTH_SHORT).show();
}
}
}
/**
* Start the upload process
*/
private void startUpload() {
if (selectedFile == null || !selectedFile.exists()) {
Toast.makeText(this, "No file selected", Toast.LENGTH_SHORT).show();
return;
}
// Update UI
progressBar.setVisibility(View.VISIBLE);
uploadButton.setEnabled(false);
resultView.setText("Uploading file...");
// Start the upload service
Intent serviceIntent = new Intent(this, FileUploadForegroundService.class);
serviceIntent.putExtra(FileUploadForegroundService.EXTRA_FILE_PATH, selectedFile.getAbsolutePath());
startService(serviceIntent);
}
/**
* Show a dialog with the upload success result
*
@@ -297,7 +407,7 @@ public class MainActivity extends AppCompatActivity {
dialog.show();
} catch (Exception e) {
Log.e(TAG, "Error showing upload result dialog", e);
Toast.makeText(this, "Upload successful! Code: " + uploadCode, Toast.LENGTH_LONG).show();
Toast.makeText(this, getString(R.string.upload_success, uploadCode), Toast.LENGTH_LONG).show();
}
});
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- Background circle -->
<path
android:fillColor="#4285F4"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2z"/>
<!-- Cloud with upload arrow -->
<path
android:fillColor="#FFFFFF"
android:pathData="M16.5,10h-1.5v-1.5c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3v1.5h-1.5c-0.83,0 -1.5,0.67 -1.5,1.5v5c0,0.83 0.67,1.5 1.5,1.5h9c0.83,0 1.5,-0.67 1.5,-1.5v-5c0,-0.83 -0.67,-1.5 -1.5,-1.5zM12,17c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1s-0.45,1 -1,1zM14,11h-4v-2.5c0,-1.1 0.9,-2 2,-2s2,0.9 2,2v2.5z"/>
<!-- Upload arrow -->
<path
android:fillColor="#FFFFFF"
android:pathData="M12,14L12,14c-0.3,0 -0.5,-0.2 -0.5,-0.5v-3c0,-0.3 0.2,-0.5 0.5,-0.5l0,0c0.3,0 0.5,0.2 0.5,0.5v3c0,0.3 -0.2,0.5 -0.5,0.5z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M13.5,12.5l-1.5,-1.5l-1.5,1.5"/>
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<!-- Simple upload icon (outline only for notification icons) -->
<path
android:fillColor="#FFFFFF"
android:pathData="M9,16h6v-6h4l-7,-7l-7,7h4V16zM5,18h14v2H5V18z"/>
</vector>

View File

@@ -1,25 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="100dp"
android:height="100dp"
android:viewportWidth="100"
android:viewportHeight="100">
<path
android:pathData="M50,50m-45,0a45,45 0,1 1,90 0a45,45 0,1 1,-90 0"
android:strokeWidth="5"
android:fillColor="#f0f0f0"
android:strokeColor="#bbb"/>
<path
android:pathData="M30,30h40v50h-40z"
android:strokeWidth="2"
android:fillColor="#ffffff"
android:strokeColor="#333"/>
<path
android:pathData="M30,30l15,0l0,15l-15,0z"
android:fillColor="#bbb"/>
<path
android:pathData="M50,40l-10,10l5,0l0,10l10,0l0,-10l5,0z"
android:fillColor="#4a90e2"/>
<path
android:pathData="M45,60h10v15h-10z"
android:fillColor="#4a90e2"/>
<!-- Background circle -->
<path
android:pathData="M50,50m-45,0a45,45 0,1 1,90 0a45,45 0,1 1,-90 0"
android:fillColor="#4285F4"/>
<!-- File with upload arrow -->
<path
android:pathData="M32,30L54,30L68,44L68,70L32,70Z"
android:fillColor="#FFFFFF"/>
<!-- Folded corner -->
<path
android:pathData="M54,30L54,44L68,44Z"
android:fillColor="#E1E1E1"/>
<!-- Upload arrow -->
<path
android:pathData="M50,50m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
android:fillColor="#34A853"/>
<path
android:pathData="M50,44L50,56"
android:strokeWidth="3"
android:strokeColor="#FFFFFF"/>
<path
android:pathData="M45,49L50,44L55,49"
android:strokeWidth="3"
android:strokeColor="#FFFFFF"/>
</vector>

View File

@@ -5,35 +5,143 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/resultView"
android:id="@+id/headerText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Looking for dumpstate..."
android:textSize="18sp"
android:text="@string/app_header"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"/>
<Button
android:id="@+id/uploadButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload Dumpstate"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/resultView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"/>
<!-- Main Upload Options Section -->
<androidx.cardview.widget.CardView
android:id="@+id/uploadOptionsCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:layout_constraintTop_toBottomOf="@id/headerText">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/upload_options_title"
android:textSize="18sp"
android:textStyle="bold"/>
<Button
android:id="@+id/selectFileButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/select_file_button"
android:drawableStart="@android:drawable/ic_menu_search"
android:paddingStart="16dp"
android:paddingEnd="16dp"/>
<Button
android:id="@+id/uploadDumpstateButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/upload_dumpstate_button"
android:drawableStart="@android:drawable/ic_menu_save"
android:paddingStart="16dp"
android:paddingEnd="16dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Dumpstate Section -->
<androidx.cardview.widget.CardView
android:id="@+id/dumpstateCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:layout_constraintTop_toBottomOf="@id/uploadOptionsCard">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dumpstate_section_title"
android:textSize="18sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/dumpstateStatusText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/looking_for_dumpstate"
android:textSize="16sp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Selected File Section -->
<androidx.cardview.widget.CardView
android:id="@+id/selectedFileCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/dumpstateCard">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/selected_file_section_title"
android:textSize="18sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/selectedFileText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/no_file_selected"
android:textSize="16sp"/>
<Button
android:id="@+id/uploadSelectedFileButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/upload_selected_file"
android:visibility="gone"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/uploadButton"
app:layout_constraintTop_toBottomOf="@id/selectedFileCard"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"/>

View File

@@ -2,12 +2,12 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_history"
android:title="Upload History"
android:title="@string/menu_history"
android:orderInCategory="100"
android:showAsAction="never" />
<item
android:id="@+id/action_settings"
android:title="Settings"
android:title="@string/menu_settings"
android:orderInCategory="200"
android:showAsAction="never" />
</menu>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">SimpleLogUpload</string>
<string name="title_activity_main">SimpleLogUpload</string>
<!-- Main UI -->
<string name="app_header">Upload Files</string>
<string name="select_file_button">Select File from Storage</string>
<string name="upload_dumpstate_button">Upload Samsung Dumpstate</string>
<string name="upload_selected_file">Upload File</string>
<string name="no_file_selected">No file selected</string>
<string name="looking_for_dumpstate">Looking for dumpstate…</string>
<string name="no_dumpstate_found">No dumpstate file found</string>
<string name="dumpstate_found">Dumpstate found: %1$s</string>
<string name="selected_file">File: %1$s</string>
<string name="uploading_file">Uploading: %1$s</string>
<string name="upload_success">Upload successful! Code: %1$s</string>
<string name="upload_error">Upload error: %1$s</string>
<string name="file_error">Error processing file: %1$s</string>
<!-- Upload options section -->
<string name="upload_options_title">Select Upload Option</string>
<string name="dumpstate_section_title">Dumpstate Detection</string>
<string name="selected_file_section_title">Selected File</string>
<!-- Menu -->
<string name="menu_history">History</string>
<string name="menu_settings">Settings</string>
<!-- Upload Dialog -->
<string name="dialog_upload_success_title">Upload Successful</string>
<string name="dialog_upload_code">Your upload code is:</string>
<string name="dialog_copy_code">Copy Code</string>
<string name="dialog_close">Close</string>
<string name="code_copied">Code copied to clipboard</string>
<!-- Permissions -->
<string name="permission_storage_required">Storage permission is required</string>
<string name="permission_not_granted">Permission not granted!</string>
</resources>

View File

@@ -0,0 +1,82 @@
package com.mattintech.simplelogupload;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.cardview.widget.CardView;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.mattintech.simplelogupload.view.MainActivity;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Unit tests for MainActivity
*/
@RunWith(AndroidJUnit4.class)
@Config(sdk = 30)
public class MainActivityTest {
private ActivityScenario<MainActivity> activityScenario;
@Before
public void setUp() {
activityScenario = ActivityScenario.launch(MainActivity.class);
}
@After
public void tearDown() {
if (activityScenario != null) {
activityScenario.close();
}
}
@Test
public void testMainActivityUIComponents() {
activityScenario.onActivity(activity -> {
// Verify UI components exist
assertNotNull(activity.findViewById(R.id.headerText));
assertNotNull(activity.findViewById(R.id.uploadOptionsCard));
assertNotNull(activity.findViewById(R.id.dumpstateCard));
assertNotNull(activity.findViewById(R.id.selectFileButton));
assertNotNull(activity.findViewById(R.id.uploadDumpstateButton));
// Verify initial state
TextView dumpstateStatusText = activity.findViewById(R.id.dumpstateStatusText);
assertNotNull(dumpstateStatusText);
// Selected file card should be hidden initially
CardView selectedFileCard = activity.findViewById(R.id.selectedFileCard);
assertEquals(View.GONE, selectedFileCard.getVisibility());
});
}
@Test
public void testFileSelectionUI() {
activityScenario.onActivity(activity -> {
// Simulate file selection
TextView selectedFileText = activity.findViewById(R.id.selectedFileText);
Button uploadSelectedFileButton = activity.findViewById(R.id.uploadSelectedFileButton);
CardView selectedFileCard = activity.findViewById(R.id.selectedFileCard);
// Initially hidden
assertEquals(View.GONE, selectedFileCard.getVisibility());
assertEquals(View.GONE, uploadSelectedFileButton.getVisibility());
// After selection (would require more complex testing with Intents)
// This is just to verify the UI logic
});
}
}