Skip to content

Conversation

@JNavas2
Copy link

@JNavas2 JNavas2 commented Dec 20, 2025

Description

This PR resolves the issue where the Aegis Quick Settings tile remains in a disabled/grayed-out state after a device reboot. The issue is consistently reproducible when Biometric Unlock is enabled.

The Problem

During a standard Android boot sequence, the LaunchAppTileService attempts to bind to the system. When Biometric Unlock is active, the app's security layer interacts with the Android Keystore. Early in the boot process (the "Direct Boot" or Credential Encrypted phase), these hardware-backed APIs are often unavailable or return security exceptions.

When the Android TileManager encounters an unhandled exception or a bind failure during this initial scan, it often "blacklists" the tile, rendering it unavailable until the user manually removes and re-adds it.

The Fix

This PR implements a "defensive" Direct Boot strategy to ensure the tile remains stable regardless of the boot timing:

  1. Direct Boot Awareness: Marked VaultLockReceiver as directBootAware="true" in the Manifest to allow it to receive system signals before the first unlock.
  2. Graceful Service Binding: Updated LaunchAppTileService to check UserManager.isUserUnlocked(). If the device is still encrypted, it sets a safe STATE_INACTIVE instead of attempting to access protected resources.
  3. Hardware-Ready Refresh: Added Intent.ACTION_USER_UNLOCKED to the VaultLockReceiver. This ensures that as soon as the user provides their first PIN/biometric unlock and the Keystore becomes available, the app forces a tile refresh via TileService.requestListeningState().

Testing Performed

  • Scenario A (Biometrics ON): Verified the tile correctly transitions from a temporary inactive state to fully enabled immediately after the first post-reboot unlock.
  • Scenario B (Biometrics OFF): Verified no change in standard behavior.
  • Scenario C (System Update): Verified the logic handles the post-update optimization refresh correctly.

Refactor onStartListening method to handle null tile case and check user unlock state.
The primary change here is adding a check for isUserUnlocked(). If the system tries to bind to the tile while the device is still in the "Direct Boot" (locked) phase, we set a safe inactive state instead of letting the binding hang or fail.
We expand this receiver to listen for ACTION_USER_UNLOCKED. When this signal is received, it calls requestListeningState(), which tells the Android system to re-bind to the tile service now that the Keystore and biometric hardware are ready.
Added permission to receive boot completed and updated VaultLockReceiver.
    Query successful
To complete your Pull Request, we must update the AndroidManifest.xml to allow the app to receive system-level signals while the device is in its "Direct Boot" (encrypted) state.
The Key Changes
1. android:directBootAware="true": This is critical. It allows the VaultLockReceiver to run before the user has provided their PIN/Fingerprint, which is when the ACTION_USER_UNLOCKED signal is first generated.
2. android:exported="true": The receiver must be exported to receive broadcasts from the Android system (like boot and unlock signals).
3. New Intent Actions: We are adding BOOT_COMPLETED and USER_UNLOCKED so the system knows to "wake up" Aegis at these specific lifecycle moments.
Added permission to receive boot completed broadcasts and removed duplicate permission entry.
This version is fully updated with the necessary permission, the directBootAware flag, and the expanded intent filters for the receiver.
Refactored for cleanliness.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant