Repository navigation
Aura v5.20.0
Aura v5.20.0
Round 3 QA audit — wallpaper/sound apply path, parallax pipeline, widget UX, and locale completeness.
Data integrity — parallax atomic writes
WallpaperApplier.prepareParallaxWallpapernow writes through a sibling.tmpfile and renames on success, with a copy+delete fallback for cross-filesystem cases.- Previously an interrupted download (process death, storage pressure, cancellation mid-stream) left a truncated image at the target path, which
ParallaxWallpaperServicewould happily load on the next surface creation and render a garbled wallpaper. - The
.tmpis now always cleaned up on failure, so orphaned partial writes can't accumulate.
Crash prevention — bitmap decode safety
WallpaperApplier.downloadBitmapnow rejects empty response bodies (IOException) and zero-dimension bounds from the first-passinJustDecodeBoundsdecode.- A corrupt or truncated image that decoded bounds to
outWidth=0would previously skip the sub-sampling math and either crash insideBitmapFactoryor decode at full resolution and OOM on a large wallpaper.
Locale correctness — finishing the v5.18.0 sweep
SoundApplier.guessMimeType+ensureFileNameExtension:Locale.ROOTon the.mp3 / .ogg / .wav / .m4a / .aac / .flacextension matching. Under Turkish locale the default lowercase could mapItoı, miss the correct MIME, fall through toaudio/mpeg, and mis-label the MediaStore entry.WallpaperRepository.nearestWallhavenColor:Locale.ROOTon the hex prefix normalization.
Widget UX — responsive feedback
FreeVibeWidget.applyRandomandapplyFromSourcenow show a "Shuffling…" toast onDispatchers.Mainbefore starting the 3–10 s network round-trip. Previously a tap produced no visible response until the wallpaper actually applied, which made the widget feel broken on slow networks.
Audit findings verified as non-issues in this pass
MainActivityintent handling — properrunCatchingaroundContentSource.valueOf,orEmpty()on nullable strings, navigation tokenization foronNewIntent. No bugs.SoundApplier.saveToMediaStorecatch-all — the MediaStore insert is explicitly rolled back (resolver.delete(uri, null, null)) whenwritten = false, so there's no orphaned row.SettingsScreen.dailyWpSharedPreferences read insideremember {}— blocks the main thread exactly once per composition. Migration to ViewModel is scope creep for a one-off setting; left as-is.
APK: Aura-v5.20.0.apk
SHA-256: c9fe5f9573d9d11f27cc8df9c170ba11bc1eedecbff1b28f90e43bdafd283a66
versionCode: 70