If you found my work helpful, buy me a coffee! It keeps me motivated ☕
This application is a proxy that completely replaces the limited, stock FM Radio app on QF-based custom Android head units with the far superior NavRadio+ (or NavRadio+free).
While its primary goal is this replacement, it also fixes two long-standing, annoying bugs that the original NavRadio+ developer has ignored and which my old Magisk module could not solve:
- The system media widget now correctly displays information from NavRadio+.
- The physical "Mode" button on the head unit now correctly cycles to the radio app.
Important: This application is a complete replacement for my obsolete Magisk module
QF_Player_proxy_module_1.2. You must uninstall the old module via Magisk before installing this application to avoid potential conflicts.
This section explains the core mechanisms used to integrate a third-party radio app into a system that is hard-coded for a stock app.
Goal: Intercept the launch from the "Mode" button cycle, launch NavRadio+, but trick the system into thinking our proxy is still in the foreground.
Mechanism:
-
Launch Detection: The system launches
FmMainActivity. We detect that the launch came specifically from the "Mode" button cycle by checking the intent's referrer. The key is thegetReferrer()method, which must match the value ofCAROUSEL_REFERRER(a constant for"com.qf.framework"). -
Launch NavRadio+: The proxy immediately finds and starts the NavRadio+ activity.
-
Applying the "Cloak": Instead of closing,
FmMainActivitycalls theapplyCloak()function. This function schedules a delayed task (350ms) that re-launchesFmMainActivityitself with theFLAG_ACTIVITY_REORDER_TO_FRONTflag. Since the activity has a@android:style/Theme.Translucent.NoTitleBartheme, it becomes an invisible window positioned on top of the now-visible NavRadio+ app. -
Swallowing the First Touch: This invisible "cloak" activity now receives all touch events. The
onTouchEventis overridden to listen forMotionEvent.ACTION_DOWN. Upon the first touch, it callsuncloakAndFinish()(which closes the invisible activity) and returnstrue. Returningtrueconsumes the event, preventing it from passing down to the NavRadio+ activity underneath. This is the "swallowed" click. -
Cleanup: A
BroadcastReceiver(finishProxyReceiver) listens for the system actionandroid.intent.action.MODE_SWITCH. This ensures that if the user presses the "Mode" button again to cycle away from the radio, the invisible cloak activity is properly closed.
Goal: Force the system media widget to update with information from NavRadio+ when the user returns to the home screen.
Mechanism:
-
Trigger: A persistent foreground service,
WidgetWatcherService, listens for theIntent.ACTION_CLOSE_SYSTEM_DIALOGSbroadcast, which is reliably triggered when the user presses the Home button. -
Audio Source Detection: Upon trigger,
checkAndFixWidget()is called. Crucially, it does not use standard Android APIs. Instead, it reads a non-standard, QF-platform-specific system property:sys.qf.last_audio_src. -
Verification: The app checks if the value of this property contains the package name for NavRadio (
com.navimods.radio). This is a 100% reliable way on this hardware to confirm that NavRadio+ was the last active audio source. -
The Hack: If verified, the service starts
FmMainActivitywith the custom actionACTION_PERFORM_HACK. This, in turn, callsperformWidgetHack(). -
Forcing the Update:
performWidgetHack()executes the core of the hack: it creates and starts anIntent.ACTION_VOICE_COMMANDaimed at a dummy activity (PseudoVoiceActivity). This system-level intent forces the platform's media manager to re-evaluate and re-query the current active media session. It fetches the latest metadata from NavRadio+ and pushes it to all system listeners, including the media widget.PseudoVoiceActivitydoes nothing and closes instantly.
To install this app as a system update and successfully bypass signature verification, you MUST meet the following requirements:
- Root Access is required.
- Magisk must be installed.
- Zygisk must be enabled in your Magisk settings.
- You must install the PMPatch Magisk Module to disable Android's signature verification check.
Failure to install PMPatch will prevent you from installing this application as a system update.
- Install the provided APK file as a simple update for the system's original FM Radio app.
- If Google Play Protect prompts you with a warning, please allow it to proceed or select "Install anyway."
- The application will automatically detect if you have
NavRadio+orNavRadio+freeinstalled. No manual selection is needed! If both are present, the paidNavRadio+version will always be prioritized.
Since the system now recognizes this app as a core system component, you cannot uninstall it directly. You have two options for removal:
- Connect your device to your computer (e.g., via WiFi ADB).
- Run the following command in your terminal:
adb uninstall com.android.fmradio.ext - Reboot your head unit.
- Go to
Settings -> Apps(orApplications). - Open the list of all apps.
- Tap the three dots (overflow menu) in the upper right corner -> Select "Show System."
- Find Radio-KM in the list.
- Tap the three dots again -> Select "Uninstall updates."
Цей застосунок є проксі, що повністю замінює обмежене, стокове FM-радіо на вашому кастомному головному пристрої на базі платформи QF на значно кращий NavRadio+ (або NavRadio+free).
Хоча його основна мета — ця заміна, він також виправляє дві давні, надокучливі помилки, які розробник NavRadio+ ігнорував, і які мій старий модуль для Magisk вирішити не міг:
- Системний медіа-віджет тепер коректно відображає інформацію з NavRadio+.
- Фізична кнопка "Mode" на головному пристрої тепер коректно перемикається на радіо.
Важливо: Цей застосунок є повною заміною мого застарілого модуля Magisk
QF_Player_proxy_module_1.2. Ви повинні видалити старий модуль через Magisk перед встановленням цього додатка, щоб уникнути потенційних конфліктів.
Цей розділ пояснює ключові механізми, використані для інтеграції стороннього радіо-додатка в систему, яка жорстко запрограмована для роботи зі стоковим.
Мета: Перехопити запуск із циклу перемикання додатків по кнопці "Mode", запустити NavRadio+, але обдурити систему, щоб вона думала, що наш проксі все ще на передньому плані.
Механізм:
-
Виявлення Запуску: Система запускає
FmMainActivity. Ми виявляємо, що запуск відбувся саме з циклу кнопки "Mode", перевіряючи реферер інтенту. Ключовим є методgetReferrer(), який має повернути значення, що відповідає константіCAROUSEL_REFERRER(що є"com.qf.framework"). -
Запуск NavRadio+: Проксі негайно знаходить і запускає активність NavRadio+.
-
Застосування "Плаща": Замість закриття,
FmMainActivityвикликає функціюapplyCloak(). Ця функція планує відкладене завдання (на 350 мс), яке перезапускаєFmMainActivityз прапоромFLAG_ACTIVITY_REORDER_TO_FRONT. Оскільки активність має тему@android:style/Theme.Translucent.NoTitleBar, вона стає невидимим вікном, що розташовується поверх щойно запущеного NavRadio+. -
Поглинання Першого Дотику: Це невидиме вікно-"плащ" тепер отримує всі події дотику. Метод
onTouchEventперевизначено для прослуховуванняMotionEvent.ACTION_DOWN. При першому дотику він викликаєuncloakAndFinish()(що закриває невидиму активність) і повертаєtrue. Поверненняtrueспоживає подію, не даючи їй дійти до активності NavRadio+ під нею. Це і є той самий "проковтнутий" клік. -
Очищення:
BroadcastReceiver(finishProxyReceiver) прослуховує системну діюandroid.intent.action.MODE_SWITCH. Це гарантує, що якщо користувач знову натисне кнопку "Mode", щоб перейти до іншого додатка, невидимий плащ буде коректно закрито.
Мета: Змусити системний медіа-віджет оновитися з інформацією від NavRadio+, коли користувач повертається на головний екран.
Механізм:
-
Тригер: Постійний сервіс,
WidgetWatcherService, прослуховує системну подіюIntent.ACTION_CLOSE_SYSTEM_DIALOGS, яка надійно спрацьовує при натисканні кнопки "Додому". -
Визначення Джерела Аудіо: Після спрацьовування тригера викликається
checkAndFixWidget(). Важливо, що він не використовує стандартні Android API. Замість цього він зчитує нестандартну, специфічну для платформи QF системну властивість (property):sys.qf.last_audio_src. -
Перевірка: Додаток перевіряє, чи містить значення цієї властивості назву пакета NavRadio (
com.navimods.radio). На цьому залізі це 100% надійний спосіб підтвердити, що NavRadio+ був останнім активним джерелом аудіо. -
Хак: Якщо перевірка успішна, сервіс запускає
FmMainActivityз кастомною дієюACTION_PERFORM_HACK. Це, у свою чергу, викликаєperformWidgetHack(). -
Примусове Оновлення:
performWidgetHack()виконує ядро хаку: створює та запускає інтентIntent.ACTION_VOICE_COMMAND, націлений на фіктивну активністьPseudoVoiceActivity. Цей інтент системного рівня змушує медіа-менеджер платформи переоцінити та перезапитати поточну активну медіа-сесію. Він отримує свіжі метадані від NavRadio+ і передає їх усім системним слухачам, включно з медіа-віджетом.PseudoVoiceActivityнічого не робить і миттєво закривається.
Щоб встановити цей додаток як системне оновлення та успішно обійти перевірку підпису, ви ПОВИННІ відповідати таким вимогам:
- Потрібен Root-доступ.
- Має бути встановлений Magisk.
- Zygisk має бути увімкнений у налаштуваннях Magisk.
- Ви повинні встановити модуль Magisk PMPatch, щоб вимкнути системну перевірку підписів:
Без встановлення PMPatch ви не зможете встановити цей додаток як системне оновлення.
- Встановіть наданий APK-файл як просте оновлення для оригінального системного FM-радіо.
- Якщо Google Play Protect покаже попередження, дозвольте йому продовжити або виберіть "Все одно встановити".
- Додаток автоматично визначить, чи встановлено у вас
NavRadio+абоNavRadio+free. Ручний вибір не потрібен! Якщо встановлено обидві версії, пріоритет завжди буде у платної версіїNavRadio+.
Оскільки система тепер розпізнає цей додаток як основний системний компонент, ви не можете видалити його безпосередньо. Є два варіанти видалення:
- Підключіть пристрій до комп'ютера (напр., через WiFi ADB).
- Виконайте в терміналі таку команду:
adb uninstall com.android.fmradio.ext - Перезавантажте головний пристрій.
- Перейдіть до
Налаштування -> Програми(абоДодатки). - Відкрийте список усіх програм.
- Натисніть на три крапки (меню) у верхньому правому куті -> виберіть "Показати системні".
- Знайдіть у списку Radio-KM.
- Знову натисніть на три крапки -> виберіть "Видалити оновлення".