FYT custom service is an Android app designed for FYT-based Android 13 head units (UIS7870 class devices). It runs a foreground service with sticky restart behavior and can execute custom code paths based on numeric parameters received through intents.
- Starts a persistent foreground service (
START_STICKY+ ongoing notification). - Uses a headless launcher activity for FYT autostart triggers (no settings UI shown if service is already running).
- Keeps manual settings access via a separate launcher entry:
FYT custom service settings. - Listens for custom broadcast intents with numeric parameters.
- Dispatches logic by command code in
FytForegroundService.executeCommand(...). - Handles FYT ACC events:
com.fyt.boot.ACCOFF: save current media app package, then sendPAUSE.com.fyt.boot.ACCON: launch saved player, wait configurable delay (default 2 seconds), sendPLAY, then restore the app that was foreground before starting the player.
- Supports ACCON startup target list (persisted on disk):
- Configure ordered app/activity starts.
- Per-target pause after launch.
- Optional default launcher activity (no explicit activity required).
- Skip target if package is already running (multi-signal running check).
- Per-target enabled checkbox (persisted).
- Provides a minimal GUI to:
- Start/stop the service.
- Show service status (
running/stopped) and last received ACCON/ACCOFF timestamps. - Change command action string.
- Toggle auto-start on boot.
- Set ACCON play delay in milliseconds (500-10000 ms).
- Configure fallback player package for ACCON when no saved player exists.
- Configure ACCON startup targets.
- Schedules a watchdog worker (15-minute periodic check) to restart the service if killed.
- Writes ACC event logs to public Documents folder (
Documents/FYTCustomService/FYTCustomService.log).
Default action:
dev.igor.fytcustomservice.ACTION_COMMAND
Extras:
extra_command_code(Int) - required command selector.extra_arg1(Int) - optional additional numeric argument.
Example ADB command:
adb shell am broadcast \
-a dev.igor.fytcustomservice.ACTION_COMMAND \
--ei extra_command_code 1 \
--ei extra_arg1 123Input broadcasts expected from FYT system:
com.fyt.boot.ACCONcom.fyt.boot.ACCOFF
ACCOFF flow:
- Read active media sessions and log all detected media controllers.
- Select the best media controller by state priority: playing, transitional states, paused, then stopped/none.
- Persist selected
packageNameusing synchronous commit. - Send media code
PAUSE.- Use media-session transport controls when the selected package has an active controller.
- Fall back to package media-button broadcast plus global
AudioManagermedia key dispatch only when transport controls are unavailable.
- Persist last-received ACCOFF timestamp.
- Append ACCOFF diagnostics to log file.
Note on play-state handling:
- Play-state detection from ACCOFF is intentionally not used anymore.
- Reason: on tested FYT firmware, media is often already paused/stopped before ACCOFF broadcast is observed, so stored state was unreliable.
- Decompiled FYT chain confirms ACCOFF broadcast dispatch (
C2444q0.m7483b(0)), and upstream ACC transition handler (C2692d.m10441i) performs mute/LCDC transitions before that broadcast. - No direct explicit media
PAUSE/STOPcall was found in that exact ACCOFF broadcast dispatch chain; this is an implementation-level inference from the inspected code paths. - Decompiled references used for this conclusion:
D:\SinoSmart\Decompiled\com.syu.ms\app\src\main\java\m1\q0.java(b(int i2), lines ~447-454): sends ACC power broadcasts from the FYT service layer.D:\SinoSmart\Decompiled\com.syu.ms\app\src\main\java\p043m1\C2444q0.java(m7483b(int i2), lines ~512-519): same ACCON/ACCOFF dispatch in obfuscated namespace.D:\SinoSmart\Decompiled\com.syu.ms\app\src\main\java\p058s0\C2692d.java(m10441i(int i2), lines ~3258-3291): ACC state update path, calls mute/LCDC handling and thenC2444q0.m7483b(i2).D:\SinoSmart\Decompiled\com.syu.ms\app\src\main\java\p043m1\C2444q0.java(m7494m(int i2), lines ~586-617;m7506y(int i2), lines ~993-1013): LCDC/amp mute control on ACC transitions.
Mute AMP logic (what it actually does):
- FYT mute-AMP path is hardware-level output muting, not media-app playback control.
- In ACC transition flow (
C2692d.m10441i), the code callsC2444q0.m7506y(...), which writes amp mute/unmute commands through JNI/native layer (ToolsJni.cmd_6_mute_amp(...)orControlNative.fytMuteAMP(...)on some variants). - Practical effect: audio output path is muted/unmuted globally at amp/MCU level.
- This is separate from media-session transport control (
PLAY/PAUSE/STOP) and does not by itself prove player state transitions.
Receiver robustness notes:
AccPowerReceiveris markeddirectBootAware=true(can receive pre-unlock phase).- Receiver first tries
startForegroundService(...)and falls back tostartService(...)if needed by firmware/runtime constraints. - Foreground service also registers a runtime ACC receiver for
com.fyt.boot.ACCON/com.fyt.boot.ACCOFFwhile service is alive. ACTION_STARTrecovery path:- if
last_acc_off_ms > last_acc_on_ms, service runs ACCON-equivalent recovery flow and logsreason=missed_acc_on_recovery. - recovery source tag is appended to trigger source (for example
missed_acc_on_recovery:watchdog).
- if
- Runtime receiver path is logged as:
RuntimeAccReceiver received action=com.fyt.boot.ACCONRuntimeAccReceiver received action=com.fyt.boot.ACCOFF
ACCON flow:
- Ignore ACCON if:
- another ACCON sequence is already in progress, or
- the previous ACCON sequence started less than 2 minutes ago.
- Cancel any still-pending delayed ACCON work from an earlier ACCON cycle.
- Capture current foreground app package before launching player/startup targets.
- If detected foreground equals player-to-launch, perform second detection excluding that player.
- If a reliable previous app still cannot be resolved, force HOME restore after startup flow.
- Load saved package from ACCOFF.
- If no saved package exists and fallback player is configured, launch fallback player, wait ACCON delay, send
PLAY.
- If no saved package exists and fallback player is configured, launch fallback player, wait ACCON delay, send
- Start saved player app.
- Wait configured delay (
ACC ON play delay, default2000ms). - Send media code
PLAYto saved player. - Execute configured ACCON startup targets in order (with per-target pauses).
- Restore previous foreground app.
- If foreground detection is unavailable, fall back to launching HOME screen.
- If previous foreground package matches
com.syu.*launcher*, use HOME intent instead of package relaunch. - Delayed restore retries are tracked and canceled if a new ACCON/ACCOFF/reset flow arrives.
- Clear saved ACCOFF package after successful ACCON handling.
- Persist last-received ACCON timestamp.
- Append ACCON diagnostics to log file.
Configured from ACC ON startup targets button in app settings screen.
Each target stores:
- Package name
- Optional activity name (blank = package default launcher activity)
- Pause after start (ms)
- Enabled flag (checkbox in editor, persisted)
Targets are persisted via device-protected SharedPreferences JSON and loaded automatically on ACCON.
Editor behavior:
- Single scrollable list (no secondary manage list).
- Single-selection model.
- Actions: Add / Edit / Delete / Move up / Move down.
- Quick enable/disable via checkbox per row (without removing target).
- App picker lists app icon, app name, and package.
- Delete requires confirmation.
- Add/Edit flow:
- Select app.
- In one combined dialog choose activity (
Default launcher activitypreselected) and delay.
A regular third-party app cannot guarantee absolutely never stopping on stock Android 13. This project uses the strongest non-root pattern available to apps:
- Foreground service with permanent notification.
START_STICKYrestart behavior.- Boot/package-replaced auto-start receiver.
- Headless launcher entry suitable for FYT "autostart after sleep" trigger.
- WorkManager watchdog restart checks.
For best reliability on FYT head units, configure these manually:
- Configure FYT "autostart after sleep" to launch
FYT custom service(headless starter). - Use
FYT custom service settingsentry when you need to open configuration UI. - Allow auto-start/background start in FYT vendor settings.
- Lock app/task in recent apps if launcher supports it.
- Keep notification permission/visibility enabled.
If you need near-system-daemon behavior, you typically need one of:
- System-app installation in
/system/priv-app. - Vendor firmware integration.
- Root + watchdog script/service manager.
Declared in manifest:
android.permission.FOREGROUND_SERVICEandroid.permission.RECEIVE_BOOT_COMPLETEDandroid.permission.WAKE_LOCKandroid.permission.PACKAGE_USAGE_STATSandroid.permission.POST_NOTIFICATIONS
Also required in system settings for full ACC logic:
- Notification access for
FYT custom service(needed to inspect active media sessions reliably). - Usage access for
FYT custom service(needed to detect/restore foreground app). - If Notification Listener access is blocked after install on Android 13, open App info for this app and allow restricted settings first, then enable Notification access.
Potentially required by device firmware:
- Vendor-specific "autostart" whitelist.
- Vendor-specific keep-alive whitelist / startup manager exception.
Release signing uses Gradle properties loaded from this project-local Gradle user home:
.gradle-user-home/gradle.properties(already gitignored)
Required keys:
RELEASE_STORE_FILERELEASE_STORE_PASSWORDRELEASE_KEY_ALIASRELEASE_KEY_PASSWORD
Log file location:
Documents/FYTCustomService/FYTCustomService.log- On Android 10+ (
targetSdk 33), writing uses MediaStore scoped-storage APIs for this path. - On older Android versions, writing uses direct file append in public Documents.
Each line starts with timestamp format:
yyyy-MM-dd HH:mm:ss.zzz(3-digit milliseconds, for example2026-04-28 14:37:05.042)
Logged details include:
- Service creation/start reason on first
onStartCommand:SERVICE start reason action=... source=... flags=... startId=...
- ACCON/ACCOFF receive events.
ACTION_STARTmissed-ACCON recovery decision (reason=missed_acc_on_recoverywhen triggered).- ACCOFF active media-controller list, selected controller, active player detection, and pause action.
- ACCON saved player launch attempt/result.
- ACCON detected foreground app before startup-target flow.
- ACCON PLAY sent to saved player.
- Media command dispatch path (
transportormedia_button+audio_manager). - Startup target actions per item: launched or skipped with reason (for example
already_running).- Includes running-check source details (
running_app_processes,foreground_usage_event,recent_foreground_without_background,not_detected).
- Includes running-check source details (
- Previous foreground restore attempt/result and delayed restore retry results.
- SYU launcher restore fallback entry:
ACCON restore detected SYU launcher package=...; using HOME intent result=...
- Cancellation of pending ACCON delayed work when a newer ACCON, ACCOFF, or reset supersedes it.
- ACCON dedup/guard events:
reason=sequence_in_progressreason=duplicate_within_window(2-minute window)
- Explicit GUI-state marker writes as
STATE ...entries:last_acc_on_ms,last_acc_off_mslast_acc_on_sequence_started_mslast_saved_player,last_saved_player_statelast_started_player,last_started_player_statelast_active_app_before_startup_targets
See CHANGELOG.md.
Implement custom command logic in:
app/src/main/java/dev/igor/fytcustomservice/FytForegroundService.kt
Method:
private fun executeCommand(code: Int, arg1: Int)
ACC/media helpers are in:
MediaControlHelper.ktMediaStateStore.ktForegroundAppHelper.kt