How the FadRec Screen Recording Accessibility Service Works in FadCam
The FadRec Screen Recording Accessibility Service leverages Android's AccessibilityService framework to run with elevated background privileges, enabling it to orchestrate MediaProjection screen captures through a static coordination flag while persisting frames to the device's FadRec storage folder.
FadCam is an open-source Android camera application that implements screen recording via a specialized service called FadRecScreenshotAccessibilityService. This service acts as the architectural bridge between the user interface and Android's low-level screen capture APIs, solving the security restriction that prevents standard background services from initiating MediaProjection requests.
Service Declaration and Permissions
Before the service can operate, it must be declared in the AndroidManifest.xml with specific permissions that grant it system-level access. The declaration includes the BIND_ACCESSIBILITY_SERVICE permission and a metadata resource defining the service configuration.
In app/src/main/java/com/fadcam/service/FadRecScreenshotAccessibilityService.java, the class extends AccessibilityService and is registered with intent filters that allow the Android system to bind it during accessibility events. The service configuration requests the FLAG_CAN_REQUEST_TOUCH_EXPLORATION_MODE flag, which is essential for receiving window state change notifications without requiring direct user interaction with the service component.
The manifest entry enables the service to remain bound in the background while the app is in use, providing the stable context required to manage MediaProjection resources across configuration changes.
Core Implementation in FadRecScreenshotAccessibilityService
The service coordinates screen capture through a state machine driven by accessibility events and static flags. This architecture decouples the UI thread from the capture logic while maintaining strict control over system resources.
Static Coordination via pendingCapture
Communication between the UI and the service relies on a static boolean flag named pendingCapture defined within the service's companion object. When the user requests a screenshot, the UI invokes FadRecScreenshotAccessibilityService.markPendingCapture(context), which sets this flag to true and acquires a partial wake lock for two seconds to ensure the CPU remains active during the transition.
The service polls this flag within onAccessibilityEvent() to determine whether the current event should trigger a capture sequence. This pattern allows the UI to remain lightweight while the service handles the heavy lifting of MediaProjection initialization.
Service Connection and Event Filtering
Upon binding, onServiceConnected() configures the service to listen for specific event types including TYPE_WINDOW_STATE_CHANGED and TYPE_VIEW_CLICKED. The method obtains a reference to the MediaProjectionManager system service, storing it for later use when the actual capture begins.
The service filters incoming accessibility events to identify the precise moment when the foreground activity matches the recording UI context. Only when pendingCapture is true and the window state event corresponds to the correct activity class does the service proceed to launch the MediaProjection intent.
Triggering Captures from the UI Layer
The entry point for screen recording is managed through ScreenShotCaptureActivity.java located in app/src/main/java/com/fadcam/. This activity serves as a thin wrapper that validates service state before requesting captures.
Service Validation
When the user taps the start recording button, the activity checks FadRecScreenshotAccessibilityService.isServiceEnabled(context) to verify the accessibility service is active in system settings. If disabled, the activity launches the system Accessibility Settings screen via Settings.ACTION_ACCESSIBILITY_SETTINGS, forcing the user to enable the service before proceeding.
Initiating the Capture Sequence
Once validated, the activity calls markPendingCapture() and immediately finishes. This design keeps the activity lifecycle brief while ensuring the service has the necessary flag state to respond to the next accessibility event. The service then detects the flag, recognizes the window state change, and launches the MediaProjection permission dialog through a hidden activity context allowed by its elevated privileges.
MediaProjection and Image Capture Flow
The actual screen capture utilizes Android's MediaProjection API combined with ImageReader surfaces to extract raw frame data from the display buffer.
VirtualDisplay and ImageReader Configuration
When startScreenCapture() executes, the service creates an ImageReader instance configured with the device's current display dimensions and PixelFormat.RGBA_8888. A VirtualDisplay is then registered with the MediaProjection instance, directing output to the ImageReader's surface.
The service implements an OnImageAvailableListener that triggers when a new frame is ready. This listener acquires the latest Image from the reader, locks the pixel buffer, and converts the raw data into a Bitmap object suitable for storage.
Resource Management and Cleanup
After extracting the frame, the service immediately releases the VirtualDisplay, closes the ImageReader, and clears the pendingCapture flag. This aggressive cleanup prevents memory leaks and ensures the MediaProjection token remains valid for subsequent captures. The bitmap is then passed to PhotoStorageHelper for persistence, naming the file with the pattern FadRec_<timestamp>.png.
Integration with FadCam UI Components
The screen recording feature integrates with several UI components to provide a seamless user experience across different application modes.
Mode Switching and State Visualization
ModeSwitcherComponent.java handles toggling between standard camera (FadCam) and screen recording (FadRec) modes. When switching to FadRec mode, the component updates badge colors and disables camera-specific controls like the lens switcher. The FadRecHomeFragment.java subclass customizes the HomeFragment layout to remove camera-dependent UI elements while exposing the screen recording trigger.
Watermark Rendering
Captured frames receive watermarks through GLWatermarkRenderer.java, which adjusts its rendering logic for FadRec mode. The renderer accounts for status bar height when positioning watermarks on screenshots, ensuring consistent branding without obstructing system UI elements.
File Persistence
The PhotoStorageHelper.java utility completes the capture pipeline by writing bitmap data to /Documents/FadRec/ (or the Pictures equivalent). It handles directory creation, file naming conventions, and media scanner notifications to ensure recordings appear immediately in gallery applications.
Summary
- FadRecScreenshotAccessibilityService.java extends Android's AccessibilityService to gain background MediaProjection privileges unavailable to standard services.
- Communication occurs via a static
pendingCaptureflag set bymarkPendingCapture()and polled duringonAccessibilityEvent(). - The service initializes MediaProjection through
createScreenCaptureIntent(), feeding frames into an ImageReader configured withRGBA_8888pixel format. - ScreenShotCaptureActivity.java validates service state and triggers captures without maintaining a persistent activity window.
- PhotoStorageHelper.java persists captured frames as timestamped PNG files in the FadRec directory, while ModeSwitcherComponent.java coordinates UI state transitions between camera and recording modes.
Frequently Asked Questions
Why does FadCam use an AccessibilityService for screen recording?
Standard Android services cannot launch MediaProjection permission requests from the background due to security restrictions introduced in recent Android versions. The AccessibilityService runs with elevated system privileges that permit it to initiate screen capture intents without requiring a visible activity window, enabling the seamless background operation required for FadRec functionality.
How does the UI communicate with the service without direct binding?
The implementation uses a static boolean flag named pendingCapture defined in FadRecScreenshotAccessibilityService.java. When the user presses the record button, the UI calls the static method markPendingCapture(), which flips this flag and acquires a brief wake lock. The service detects this state change during its next onAccessibilityEvent() callback and initiates the capture sequence.
What happens if the AccessibilityService is disabled while recording?
If the user disables the service in system settings during an active recording session, the MediaProjection instance remains valid until explicitly stopped, but new captures cannot be initiated. The isServiceEnabled() check in ScreenShotCaptureActivity.java prevents starting new recordings until the service is re-enabled, ensuring the app never attempts unauthorized capture requests.
Where are FadRec screenshots saved on the device?
Captured screenshots are saved to the device's shared storage directory (typically /Documents/FadRec/ or /Pictures/FadRec/) via PhotoStorageHelper.java. Files follow the naming convention FadRec_<timestamp>.png, making them immediately accessible through standard gallery applications and file managers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →