All notable changes to Azkura Auth Android are documented here.
The format is inspired by Keep a Changelog, and versioning follows the app's Android versionName / versionCode metadata.
- Gallery QR scan (root cause, not just symptoms). The previous
implementation required
READ_MEDIA_IMAGES/READ_EXTERNAL_STORAGEand drove gallery import through a legacyACTION_PICKintent; if the user denied that permission (common on Android 13+) gallery import was completely blocked, even though the modern permission-less Photo Picker was already wired up but never actually called. RewroteScannerScreen.ktto useActivityResultContracts.PickVisualMedia(official Android Photo Picker, no runtime permission required) as the primary path, withGetContent()as an automatic fallback viaisPhotoPickerAvailable()for devices without a compatible picker.READ_MEDIA_IMAGES/READ_EXTERNAL_STORAGEare no longer declared in the manifest (least-privilege). - Gallery QR: bitmap decode + ContentResolver I/O now run on
Dispatchers.IOinstead of the Compose main thread, so a large photo or a not-yet-cached cloud gallery item (Google Photos) can no longer stall the UI. - Gallery QR: EXIF orientation is now read via
androidx.exifinterfaceand passed toInputImage.fromBitmap(bitmap, rotationDegrees), improving decode success for portrait/rotated photos.
- Auto Backup after Google login. Signing in with Google now
automatically triggers a backup to Drive in the background (no blocking
UI), with up to 3 retries using exponential backoff on transient
failures, and structured
Log.d/w/elogging (SettingsViewModel,GoogleDriveService) for debugging. - Auto Restore after Google login. After login, the app checks Google
Drive for an existing backup and restores it automatically if found.
Restore uses the existing additive merge (
mergeAccounts/mergeFolders) which only adds missing accounts/folders and never deletes or overwrites local data, so an older or already-merged backup can never cause data loss. Backups with missing/unparseable metadata are skipped defensively. - Classified Google sign-in errors (
GoogleSignInException): cancelled, no network, token error, session expired, Play services problem, or timeout (25s) — each with a specific, actionable Indonesian message instead of a raw SDK exception string. - Small, non-blocking auto-sync status indicator + animated Connect/Backup button state (spinner + label) in Settings, instead of a static "Connect" label with no feedback while the request is in flight.
- Recent Apps preview. The app previously showed a solid black
thumbnail in the Recents/App Switcher because
FLAG_SECUREblocks the OS from capturing any image of the window, including the Recents snapshot. Added a ComposePrivacyOverlaythat is shown beforeFLAG_SECUREis briefly cleared inonPause()(so the Recents snapshot captures only the safe, branded blurred overlay) andFLAG_SECUREis restored before the overlay is hidden again inonResume(). No sensitive content is ever exposed to a screenshot/recording at any point — security level is unchanged, only the Recents thumbnail's appearance improves.
- Gallery QR: downsample large images. Screenshots (1080x2392+) now get downsampled to max 1024px on the longest side before ML Kit processes them, preventing OOM and scan failures on large gallery images.
- Gallery QR: switch from
InputImage.fromFilePath()tocontentResolver.openInputStream()→BitmapFactory.decodeStream()→InputImage.fromBitmap()which works reliably on Xiaomi/MIUI devices. - Gallery QR: configure ML Kit to scan QR_CODE, AZTEC, and DATA_MATRIX formats specifically for higher detection success rate.
- Gallery QR: detailed error messages now include
e.messagefor easier debugging.
- Gallery QR: replace invalid Kotlin
return@trylabels withreturn@processGalleryUri.
- Xiaomi/MIUI gallery import fix. Added
READ_MEDIA_IMAGESandREAD_EXTERNAL_STORAGE(maxSdkVersion=32) permissions to manifest. - Scanner now requests storage permission before opening gallery — MIUI requires explicit permission for gallery access instead of relying on the Photo Picker.
- Three-strategy fallback: permission request → ACTION_PICK → GetContent.
- Centralized
processGalleryUri()to deduplicate image processing logic across all launcher types.
- Gallery import now uses permission-based approach instead of
PickVisualMediawhich silently fails on Xiaomi/MIUI.
- Gallery QR race condition. Camera scanner now pauses
(
isGalleryActiveflag) while the gallery picker is open, preventing the camera from stealing the scan via race condition. - Gallery import errors auto-dismiss after 8 seconds instead of 4 seconds so users have time to read them.
- Auto-backup to Google Drive after adding a new account. Uses a 10-second debounce (multiple adds within 10s trigger one backup) and a 5-minute rate limit. Silent operation — logs only, no UI blocking.
lastAutoBackupAtpersistence inPreferencesManagerfor rate limiting across app restarts.
- Auto-backup respects user's encryption setting and skips silently if Google is not connected, token is expired, or encryption is enabled without a backup password.
- Google login success animation — dialog now uses
AnimatedVisibilitywith fade-in + slide-in, shows checkmark icon and "Berhasil!" title for success messages. - Token purge on app startup — expired Google OAuth tokens are automatically cleaned up during cold start to prevent silent failures.
- Gallery import: add
isPhotoPickerAvailable()check withACTION_GET_CONTENTfallback for devices without Android Photo Picker.
- GitHub Actions CI/CD pipeline. Unified workflow for debug APK, signed release AAB/APK, and GitHub Release publishing on version tags. Secrets validation ensures build fails if signing credentials are missing.
- Modular cloud sync provider architecture. New
CloudSyncProviderinterface enables adding new cloud backup providers (OneDrive, Dropbox, etc.) through configuration only — no changes to UI or ViewModel code. Providers registered via Hilt@Binds @IntoSetmultibinding. GoogleDriveSyncProvider— wraps existing Google Auth + Drive services behind the new interface.CloudSyncProviderRegistry— query providers by ID, discover available providers, no hardcoding.AuthConfigManager— non-sensitive provider configuration backup (never backs up tokens, keys, or secrets).- Provider-agnostic methods in
SettingsViewModel(onConnectProvider,onBackupToProvider,onRestoreFromProvider) alongside existing Google-specific methods for backward compatibility. docs/CICD_SECRETS.md— full documentation of all required GitHub Secrets for the CI/CD pipeline.
- Removed old
release.ymlworkflow, replaced by unifiedbuild-release.yml. - Release signing reads from
keystore.properties→ Gradle properties → environment variables (GitHub Actions).
- No credentials stored in repository. Keystore file is base64-encoded in GitHub Secrets only. OAuth Client IDs are public (safe in APK).
- Import QR code from gallery. The scanner screen now has a gallery action
that decodes an
otpauth://QR from any saved image using the Android Photo Picker (no storage/media permission required on any supported API level). - No-camera device support. Devices without a camera (or with the camera permission denied) now get a clear message and can still add accounts via the gallery import path instead of being stuck.
- R8 code shrinking/obfuscation for release builds with a curated
proguard-rules.pro(keeps serialization models, Room, Hilt, Retrofit, ML Kit, and Google Sign-In working while obfuscating internals). network_security_config.xmlthat forbids cleartext (HTTP) traffic app-wide — including on Android 8.0–8.1 where it is not the platform default — and pins Google API TLS certificates (googleapis.com) at the CA level with a fail-open expiration date.- GitHub Actions workflow that assembles and signs the release APK and attaches it to a GitHub Release.
- Build-breaking bug: PIN removal called
onRemovePin()without the requiredcurrentPinargument, so the project failed to compile. Removing a PIN now shows a confirmation dialog that re-verifies the current PIN first (closes the privilege-escalation gap and restores compilation). - Crash hardening: a single malformed/corrupted TOTP secret could throw inside the once-per-second refresh loop and freeze every code on the Home screen. Code generation is now guarded per account and the refresh loop is crash-safe.
- Scanning, gallery import, and adding an account no longer crash on unsupported
devices, unreadable images, non-
otpauthQR codes, or invalid Base32 secrets — each case surfaces a friendly message instead.
- Add Account now validates the secret is real Base32 before saving, so an unusable account can never reach the vault or the TOTP generator.
- Removed the dead, unencrypted local backup export path (
exportToUri); all local exports go through the encrypted.vaultflow. - Usage statistics (
app_stats.json) are now stored encrypted with the Keystore-backed encryptor instead of plaintext JSON (with transparent migration of any existing plaintext file). - Upgraded
androidx.security:security-cryptofrom1.1.0-alpha06to the stable1.1.0and migrated off the deprecatedMasterKeysAPI.
- Resolves the remaining open hardening issues: release obfuscation (#12), TLS certificate pinning (#13), plaintext local export (#14), unprotected usage metadata (#15), and missing network security config (#16).
- Professional repository documentation: README, About, Privacy, Security, Contributing, and Release Notes.
- MIT license file.
- Stronger
.gitignorerules for signing files, local configuration, secrets, and generated release artifacts.
- Tightened
otpauth://parsing so the queryissueris the primary identity source. - Improved service logo lookup hierarchy: issuer, label issuer, sanitized keyword, then fallback initials.
- Prevented email domains from being used as service-logo identity hints.
- Debug Kotlin compilation passed.
- Unit test task passed.
- Release APK assembled successfully.
- Release APK signing verified with Android SDK
apksigner.
- Animated Statistics screen micro-interactions including counters, chart/progress fills, and staggered entrances.
- Reusable service logo component shared by Home and Statistics.
- Bundled offline brand assets for popular services and crypto/Web3 accounts.
- Home account cards now use the universal service logo pipeline.
- Statistics Top Services now uses the same logo rendering behavior as Home.
- Persistent sort order preference with Custom, Alphabetical, Most Used, and Recently Added modes.
- Sort Order bottom sheet in Settings with dynamic selected-state indicator.
- Long-press drag-and-drop custom ordering on Home.
- Visual and haptic feedback while reordering accounts.
- Updated launcher icon resources.
- Home list sorting now reacts to DataStore preference changes.
- Manual account reordering is active only in Custom sort mode.
- Custom order persistence happens after drop using a batch database update.