feat(ui): add test notification preference and optimize Android TV logic

Introduce a "Test Notification" preference in the settings menu to allow users to verify the notification system. This preference is automatically hidden on Android TV devices to maintain a clean UI.

Additionally, refactor notification permission handling to skip requests on Android TV and improve the internal check for Leanback support using a lazy property.

Updated string resources for the new preference across all supported languages.
This commit is contained in:
2026-05-30 22:15:51 +02:00
parent 23079649c5
commit 1879827f4b
12 changed files with 54 additions and 15 deletions
@@ -35,17 +35,16 @@ class MainActivity : AppCompatActivity() {
/* Main class variables */
private lateinit var appBarConfiguration: AppBarConfiguration
// Check if the device running the app is an Android TV instance
private val isAndroidTV: Boolean by lazy {
packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
}
// request notification permission (for Android 13+)
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
NotificationSys.showNotification(
this,
R.string.app_name,
R.string.notification_test_content
)
} else {
if (!isGranted) {
Snackbar.make(
findViewById(android.R.id.content),
R.string.snackbar_failed_permission_notification,
@@ -95,7 +94,7 @@ class MainActivity : AppCompatActivity() {
supportActionBar?.hide()
// TV-specific loading logic: Hide the overlay once the app is ready
if (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
if (isAndroidTV) {
Handler(Looper.getMainLooper()).postDelayed({
hideLoadingOverlay()
}, 1200)
@@ -107,14 +106,8 @@ class MainActivity : AppCompatActivity() {
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
// request permissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!isAndroidTV && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
} else {
NotificationSys.showNotification(
this,
R.string.app_name,
R.string.notification_test_content
)
}
}
@@ -22,6 +22,8 @@ import com.michatec.radio.dialogs.PresetSelectionDialog
import com.michatec.radio.dialogs.ThemeSelectionDialog
import com.michatec.radio.dialogs.YesNoDialog
import com.michatec.radio.helpers.*
import com.michatec.radio.NotificationSys
import android.content.pm.PackageManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
@@ -38,6 +40,11 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
/* Define log tag */
private val TAG: String = SettingsFragment::class.java.simpleName
// Check if the device running the app is an Android TV instance
private val isAndroidTV: Boolean by lazy {
packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
}
/* Overrides onViewCreated from PreferenceFragmentCompat */
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -309,6 +316,21 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
return@setOnPreferenceClickListener true
}
// set up "Test Notification" preference
val preferenceTestNotification = Preference(context)
preferenceTestNotification.title = getString(R.string.pref_test_notification_title)
preferenceTestNotification.setIcon(R.drawable.ic_notification_app_icon_white_24dp)
preferenceTestNotification.summary = getString(R.string.pref_test_notification_summary)
preferenceTestNotification.setOnPreferenceClickListener {
// show test notification
NotificationSys.showNotification(
context,
getString(R.string.pref_test_notification_title),
getString(R.string.notification_test_content)
)
return@setOnPreferenceClickListener true
}
// set up "Security" preference
val preferenceSecurity = Preference(context)
preferenceSecurity.title = getString(R.string.pref_security_title)
@@ -364,6 +386,10 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
preferenceCategoryGeneral.addPreference(preferenceThemeSelection)
preferenceCategoryGeneral.addPreference(preferenceLanguageSelection)
if (!isAndroidTV) {
preferenceCategoryGeneral.addPreference(preferenceTestNotification)
}
screen.addPreference(preferenceCategoryAudioEffects)
preferenceCategoryAudioEffects.addPreference(preferenceBassBoost)
preferenceCategoryAudioEffects.addPreference(preferenceReverb)