14 KiB

🔧 Troubleshooting Guide

Common Issues & Solutions

🚨 Build Issues

Issue 1: Gradle Sync Failed

Error: Gradle sync failed: Failed to resolve...

Solutions:

  1. Clean project: BuildClean Project
  2. Invalidate caches: FileInvalidate Caches / Restart
  3. Sync Gradle: FileSync Now
  4. Delete .gradle folder and try again
  5. Check internet connection (gradle downloads dependencies)

Issue 2: Missing Dependencies

Error: Unresolved reference: LocationValidator atau similar

Solutions:

  1. Verify file exists in correct package structure
  2. Check package declaration at top of file
  3. Rebuild project: BuildRebuild Project
  4. Check that all imports are present
  5. File → Invalidate Caches / Restart

Issue 3: Kotlin Syntax Error

Error: Type mismatch: inferred type is String? but Boolean was expected

Solutions:

  1. Check null-safety: use ?. or !! appropriately
  2. Verify data class properties match their types
  3. Look for missing type annotations
  4. Check imports for correct classes

📍 Location Issues

Issue 1: GPS Not Acquiring Location

Error: "Lokasi tidak tersedia"

Causes & Solutions:

  • Location permission not granted → Check Settings → Apps → Permissions → Location (Allow)

  • Location services disabled → Enable in Settings → Location → Location Services

  • Cold start GPS (takes time to acquire) → Wait 30-60 seconds for GPS to warm up → Or enable "Use high accuracy" in location settings

  • Testing in emulator → Use Extended Controls → Location to simulate GPS → Or use GPX file for GPS simulation

Quick Check:

// Test if GPS is available
val hasLocationPermission = ContextCompat.checkSelfPermission(
    context, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED

// Test if location services enabled
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)

Issue 2: Location Always Invalid

Error: "✗ Lokasi tidak valid (2500m, maksimal 100m)"

Causes & Solutions:

  • Reference coordinates wrong → Update REFERENCE_LATITUDE dan REFERENCE_LONGITUDE di AttendanceConfig.kt → Verify with Google Maps

  • Radius too small → Increase ALLOWED_RADIUS_METERS temporarily for testing → Default is 100m, try 200m or 300m

  • Testing from wrong location → Go to actual campus location → Or use emulator GPS simulation

How to Fix:

// File: AttendanceConfig.kt
const val REFERENCE_LATITUDE = -7.025    // ← Update this
const val REFERENCE_LONGITUDE = 110.415  // ← Update this
const val ALLOWED_RADIUS_METERS = 100.0  // ← Or increase this

How to Verify Reference Coordinates:

  1. Go to campus location with device
  2. Open Google Maps
  3. Long-click on map → Coordinates appear at top
  4. Copy latitude and longitude
  5. Update in AttendanceConfig.kt

Issue 3: Distance Calculation Wrong

Error: Shows 5000m distance when clearly close to reference

Causes & Solutions:

  • Latitude/longitude swapped → Check: latitude is first, longitude is second → Format should be: (-7.025, 110.415) not (110.415, -7.025)

  • Wrong location acquired → Check Logcat: Log.d("Location", "Lat: $lat, Lon: $lon") → Verify with Google Maps

  • Haversine formula bug → Run unit tests: ./gradlew test → Check LocationValidatorTest results

Debug Steps:

// Add logging to MainActivity
Log.d("AbsensiApp", "Reference: -7.0, 110.4")
Log.d("AbsensiApp", "Student: ${state.location?.latitude}, ${state.location?.longitude}")
Log.d("AbsensiApp", "Distance: ???")

// Or test manually
val distance = LocationValidator.calculateDistance(
    -7.0, 110.4,
    -7.0035, 110.4042
)
Log.d("Distance Test", "Result: $distance meters")

📸 Camera Issues

Issue 1: Camera Permission Denied

Error: "Izin kamera ditolak"

Solutions:

  1. Open Settings → Apps → YourApp → Permissions
  2. Find "Camera" permission
  3. Tap it → Select "Allow"
  4. Return to app and try again

For Emulator:

  1. Device Manager → Create/Edit device
  2. Verify "Camera" is checked in hardware
  3. Set Camera: "Emulated"

Issue 2: Photo Not Captured

Error: Camera opens but no photo saved

Causes & Solutions:

  • User canceled camera intent → Just tap button again to retry

  • Storage permission issue (older Android) → Grant WRITE_EXTERNAL_STORAGE in Settings

  • Camera intent failure → Check if device has camera: hasSystemFeature(PackageManager.FEATURE_CAMERA)

Debug:

// Check in logcat
Log.d("Camera", "Result Code: $resultCode")
Log.d("Camera", "Data: ${result.data}")
Log.d("Camera", "Bitmap: ${bitmap != null}")

Issue 3: Photo Preview Not Showing

Error: PhotoPreviewCard shows "Belum ada foto"

Causes & Solutions:

  • Bitmap is null → Check Activity.RESULT_OK returned → Verify result.data?.extras?.getParcelable working

  • UI not updating → Ensure state.copy() is called → Check LaunchedEffect dependencies

Quick Fix:

// Add logging
if (bitmap != null) {
    Log.d("Photo", "Bitmap size: ${bitmap.width}x${bitmap.height}")
    state = state.copy(foto = bitmap)
} else {
    Log.d("Photo", "Bitmap is null!")
}

🌐 Network Issues

Issue 1: Cannot Connect to Webhook

Error: "Gagal kirim ke server" or timeout

Causes & Solutions:

  • No internet connection → Check WiFi/mobile data enabled → Ping google.com to verify

  • Wrong webhook URL → Verify in AttendanceConfig.kt → Copy exact URL from N8n dashboard

  • Firewall/VPN blocking → Disable VPN temporarily → Check if institution firewall allows HTTPS

  • N8n server down → Test with curl: curl -X POST https://n8n.lab.ubharajaya.ac.id/webhook/... → Check N8n status page

Webhook URL Check:

// File: AttendanceConfig.kt
const val WEBHOOK_PRODUCTION = "https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254"
// ↑ Copy exact URL, no typos!

Issue 2: Server Returns 400/500 Error

Error: "Absensi ditolak server" with error code

Causes & Solutions:

  • Status 400: Data format wrong → Verify JSON structure matches expectations → Check all fields are present (npm, nama, lat, lon, foto) → Check foto is valid Base64

  • Status 401: Authentication failed → Add authentication token if required → Contact server admin

  • Status 500: Server error → Check N8n workflow logs → Verify database connection → Retry after server is fixed

Test with Test Webhook First:

// In MainActivity
isTest = true  // Set this to test first
// Check results at: https://n8n.lab.ubharajaya.ac.id/webhook-test/...

Issue 3: Timeout (Takes Too Long)

Error: Request hangs for 30+ seconds then fails

Solutions:

  1. Check network speed: Test with speed.test.com
  2. Reduce photo size: Decrease PHOTO_QUALITY in AttendanceConfig.kt
  3. Increase timeout: Change API_TIMEOUT_MS (but not recommended)
  4. Check server response time (might be slow)
// File: AttendanceConfig.kt
const val PHOTO_QUALITY = 70      // Reduce from 80 to 70
const val API_TIMEOUT_MS = 30000  // Current 30 seconds

⚙️ Permission Issues

Issue 1: Permission Dialog Not Appearing

Error: App crashes or silently fails

Solutions:

  1. Verify permission in AndroidManifest.xml:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    
  2. Check permission launcher is called:

    LaunchedEffect(Unit) {
        locationPermissionLauncher.launch(
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    }
    
  3. For Android 12+, check targetSdk:

    targetSdk = 36
    

Issue 2: Permission Stuck on Denied

Error: User clicks "Deny" and can't recover

Solutions:

  1. User must go to Settings manually: → Settings → Apps → YourApp → Permissions → Allow

  2. Add UI hint in app:

    if (state.errorMessage?.contains("Izin") == true) {
        Button("Buka Pengaturan") {
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            startActivity(intent)
        }
    }
    

💾 Data & State Issues

Issue 1: Form Not Validating

Error: Submit button always disabled or always enabled

Causes & Solutions:

  • Validation logic wrong → Check LocationValidator.isLocationValid() implementation → Run unit tests: ./gradlew test

  • State not updating → Verify state.copy() being called → Check all conditions in button enabled state

Validation Checklist:

// Button should be enabled only when ALL true:
val canSubmit = (
    state.location != null &&                    // Location acquired
    state.foto != null &&                        // Photo taken
    state.validationResult.isValid &&            // Location valid
    !state.isLoadingSubmit                       // Not currently submitting
)

SubmitButtonWithLoader(
    // ...
    isEnabled = canSubmit  // ← Check this
)

Issue 2: State Lost on Screen Rotation

Error: Form data disappears when device rotates

Solutions: This is normal - Compose restores state automatically via remember {}

To persist across full app restart:

// Would need ViewModel + SavedStateHandle (advanced feature)
// Currently: state is reset on process death (acceptable for MVP)

Issue 3: Photo Bitmap Memory Issue

Error: "OutOfMemoryError: Bitmap too large" or app crashes

Solutions:

  1. Reduce photo quality:

    const val PHOTO_QUALITY = 60  // Reduce from 80
    
  2. Compress after capture:

    // In bitmapToBase64:
    bitmap.compress(Bitmap.CompressFormat.JPEG, PHOTO_QUALITY, outputStream)
    
  3. For low-memory devices:

    • Scale down bitmap before encoding
    • Or use WebP format (better compression)

🧪 Testing Issues

Issue 1: Unit Tests Not Running

Error: "No tests found" or tests fail

Solutions:

  1. Run from command line:

    ./gradlew test
    
  2. Or in Android Studio:

    • Right-click test file → Run 'LocationValidatorTest'
    • Or use Test Configuration
  3. Verify test file location:

    app/src/test/java/.../LocationValidatorTest.kt  ✓ Correct
    app/src/androidTest/java/.../LocationValidatorTest.kt  ✗ Wrong
    

Issue 2: Manual Testing Stuck

Error: Can't reproduce the flow

Quick Test Checklist:

  • Device/emulator has internet
  • Location services enabled
  • All permissions granted
  • Camera app works
  • Webhook URL correct

Fastest Flow:

  1. Grant permissions automatically
  2. Hardcode valid location (for testing)
  3. Take photo
  4. Click submit
  5. Should complete in < 10 seconds

🎨 UI Issues

Issue 1: Layout Cut Off on Small Screens

Error: Buttons/text not visible

Solutions:

  1. Already implemented: verticalScroll(rememberScrollState())
  2. Reduce padding: modifier.padding(16.dp)modifier.padding(8.dp)
  3. Use Column scrolling instead of fixed height
Column(
    modifier = modifier
        .fillMaxSize()
        .padding(16.dp)
        .verticalScroll(rememberScrollState())  // ← This allows scrolling
)

Issue 2: Dark Mode Not Working

Error: Text hard to read or colors wrong

Solutions:

  1. Theme already supports dynamic colors (Material 3)
  2. Verify Theme.kt has proper dark/light variants
  3. Test: Settings → Display → Dark theme → On/Off

Issue 3: Loading Spinner Not Showing

Error: Button says "Mengirim..." but no spinner

Solutions:

  1. Check isLoading state is true:

    state = state.copy(isLoadingSubmit = true)
    
  2. Verify spinner code in SubmitButtonWithLoader:

    if (isLoading) {
        CircularProgressIndicator(...)  // ← Should show
    }
    

🆘 Emergency Troubleshooting

App Crashes on Launch

  1. Check Logcat for full error stack trace
  2. Look for line number where crash happens
  3. Most common: Missing permission or dependency
  4. Try: BuildClean ProjectRebuild Project

Complete State Reset

# Uninstall app completely
./gradlew uninstallDebug

# Clean all build artifacts
./gradlew clean

# Rebuild everything
./gradlew installDebug

Last Resort: Check Dependencies

// Verify all dependencies installed
./gradlew dependencies

// Check for conflicts
./gradlew dependencyInsight --dependency location-services

📊 Debugging Commands

View All Logs

adb logcat

Filter Specific Tags

adb logcat | grep "AbsensiApp"
adb logcat | grep "N8nService"
adb logcat | grep "LocationValidator"

Clear Logs

adb logcat -c

Install Debug App

./gradlew installDebug

Uninstall App

adb uninstall id.ac.ubharajaya.sistemakademik

View App Logs in Real-time

adb logcat *:S AbsensiApp:D

🔍 Verification Checklist

Before declaring bug fixed, verify:

  • Issue is reproducible
  • Logs show no errors
  • All permissions granted
  • Internet connection active
  • Coordinates correct
  • Server responding
  • Photo quality acceptable
  • Location accuracy good
  • Form submission successful
  • Data received at webhook

Still stuck?

  1. Re-read QUICK_REFERENCE.md
  2. Check DOKUMENTASI.md for detailed explanations
  3. Review TESTING_CHECKLIST.md for testing procedures
  4. Check ARCHITECTURE.md for design understanding
  5. Look at comments in actual code files

Last Updated: January 14, 2026
Version: 1.0