diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 15e590af4..122b870eb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,6 @@
-
diff --git a/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt b/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt
index 250b409b9..1602e4c98 100644
--- a/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt
+++ b/app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt
@@ -17,28 +17,22 @@
package org.akanework.gramophone.logic
-import android.Manifest
import android.annotation.SuppressLint
-import android.app.NotificationChannel
-import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
-import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.media.AudioManager
import android.media.audiofx.AudioEffect
import android.net.Uri
-import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.concurrent.futures.CallbackToFutureAdapter
-import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
@@ -84,7 +78,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import org.akanework.gramophone.BuildConfig
import org.akanework.gramophone.R
-import org.akanework.gramophone.logic.ui.MyRecyclerView
import org.akanework.gramophone.logic.utils.CircularShuffleOrder
import org.akanework.gramophone.logic.utils.LastPlayedManager
import org.akanework.gramophone.logic.utils.LrcUtils.LrcParserOptions
@@ -98,8 +91,6 @@ import org.akanework.gramophone.logic.utils.exoplayer.EndedWorkaroundPlayer
import org.akanework.gramophone.logic.utils.exoplayer.GramophoneMediaSourceFactory
import org.akanework.gramophone.logic.utils.exoplayer.GramophoneRenderFactory
import org.akanework.gramophone.ui.MainActivity
-import org.akanework.gramophone.ui.components.LegacyLyricsAdapter
-import org.akanework.gramophone.ui.components.NewLyricsView
import kotlin.random.Random
@@ -128,13 +119,8 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
const val SERVICE_GET_LYRICS_LEGACY = "get_lyrics_legacy"
const val SERVICE_GET_SESSION = "get_session"
const val SERVICE_TIMER_CHANGED = "changed_timer"
- private const val FLAG_ALWAYS_SHOW_TICKER = 0x01000000
- private const val FLAG_ONLY_UPDATE_TICKER = 0x02000000
}
- private var newView: NewLyricsView? = null
- private var recyclerView: MyRecyclerView? = null
- private val adapter
- get() = recyclerView?.adapter as LegacyLyricsAdapter?
+
private var lastSessionId = 0
private var mediaSession: MediaLibrarySession? = null
private var controller: MediaController? = null
@@ -148,7 +134,6 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
private lateinit var lastPlayedManager: LastPlayedManager
private val lyricsLock = Semaphore(1)
private lateinit var prefs: SharedPreferences
- private var highLyric : String = ""
private fun getRepeatCommand() =
when (controller!!.repeatMode) {
@@ -388,7 +373,6 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
headSetReceiver,
IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
)
- startTimer()
}
// When destroying, we should release server side player
@@ -673,139 +657,6 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
}
}
- fun startTimer() {
- val handler = Handler(Looper.getMainLooper())
- val runnable = object : Runnable {
- override fun run() {
- lyric()
- handler.postDelayed(this, 100)
- }
- }
- handler.post(runnable) // 启动定时器
- }
-
- fun lyric() {
- val getLyricsLegacy = controller?.getLyricsLegacy()
- val getLyrics = controller?.getLyrics()
- updateLyrics(getLyricsLegacy, getLyrics)
- val highlightedLyric = getCurrentHighlightedLyric()
- if (highlightedLyric != null) {
- sendlyric(highlightedLyric)
- } else {
- null
- }
-
- }
-
- private fun sendlyric(Lyrics: String) {
- if (highLyric != Lyrics ) {
- highLyric = Lyrics
- val isLyricUIEnabled = prefs.getBoolean("lyric_statusbarLyric", true)
- if (isLyricUIEnabled == true ){
- sendMeiZuStatusBarLyric(Lyrics,isLyricUIEnabled)
- } else {
- sendMeiZuStatusBarLyric("",isLyricUIEnabled)
- }
- //Log.d(TAG,"当前高亮歌词: $Lyrics")
-
- }
-
- }
- private fun sendMeiZuStatusBarLyric(Lyrics: String, open: Boolean) {
- val channelId = "StatusBarLyric"
- val channelName = getString(R.string.settings_lyrics_StatusBarLyric)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val importance = NotificationManager.IMPORTANCE_MIN // 设为低优先级,避免打扰用户
- val channel = NotificationChannel(channelId, channelName, importance)
- channel.description = getString(R.string.settings_lyrics_StatusBarLyric)
-
- val notificationManager = applicationContext.getSystemService(NotificationManager::class.java)
- notificationManager.createNotificationChannel(channel)
- }
- val notification = NotificationCompat.Builder(applicationContext, channelId)
- notification.setSmallIcon(R.drawable.ic_gramophone_monochrome) // 确保图标存在且有效
- .setContentTitle(getString(R.string.settings_lyrics_StatusBarLyric)) // 通知标题,例如歌曲名称
- .setContentText(Lyrics) // 通知正文,例如歌手和专辑信息
- .setTicker(Lyrics) // 设置状态栏歌词滚动内容
- .setPriority(NotificationCompat.PRIORITY_MIN) // 低优先级,避免打扰
- .setOngoing(true) // 设置为持续通知,用户无法轻易滑掉通知
- val StatusBar = notification.build()
- //发送图标
- StatusBar.extras.putInt("ticker_icon", R.drawable.ic_gramophone_monochrome)
- StatusBar.extras.putBoolean("ticker_icon_switch", false)
- // 设置自定义 FLAG,确保只更新状态栏歌词,不更新其他内容
- // 保持状态栏歌词滚动显示
- StatusBar.flags = StatusBar.flags.or(FLAG_ALWAYS_SHOW_TICKER)
- // 只更新 Ticker(歌词),不会更新其他属性
- StatusBar.flags = StatusBar.flags.or(FLAG_ONLY_UPDATE_TICKER)
- // 检查是否需要请求通知权限(针对 Android 13 及以上)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- if (ActivityCompat.checkSelfPermission(
- this,
- Manifest.permission.POST_NOTIFICATIONS
- ) != PackageManager.PERMISSION_GRANTED
- ) {
- // 如果在 Service 中没有权限,我们不能直接请求权限,因此需要在启动 Service 前确保权限已被授予
- // 这里可以记录日志或通知调用方权限没有授予
- Log.e("GramophoneService", "Notification permission not granted.")
- return
- } else {
- // 已经有权限,直接发送通知,要是开关关闭则关闭通知
- if (open == true ) {
- NotificationManagerCompat.from(applicationContext).notify(2, StatusBar)
- } else {
- NotificationManagerCompat.from(applicationContext).cancel(2)
- }
- }
- } else {
- // 低于 Android 13,不需要请求通知权限,直接发送通知
- if (open == true ) {
- NotificationManagerCompat.from(applicationContext).notify(2, StatusBar)
- } else {
- NotificationManagerCompat.from(applicationContext).cancel(2)
- }
- }
- }
-
-
- private fun updateNewIndex(): Int {
- val filteredList = lyricsLegacy?.filterIndexed { _, lyric ->
- (lyric.timeStamp ?: 0) <= (controller?.currentPosition ?: 0)
- }
-
- return if (filteredList?.isNotEmpty() == true) {
- filteredList.indices.maxByOrNull {
- filteredList[it].timeStamp ?: 0
- } ?: -1
- } else {
- -1
- }
- }
-
-
- fun getCurrentHighlightedLyric(): String? {
- val position = updateNewIndex()
- return if (position != -1) {
- lyricsLegacy?.get(position)?.content // 返回高亮的歌词内容
- } else {
- null // 没有高亮的歌词
- }
- }
-
-
- fun updateLyrics(parsedLyrics: MutableList?, parsedLyricsa: SemanticLyrics?) {
- if ( parsedLyrics.toString() == "null" ){
- lyricsLegacy = SemanticLyrics.convertForLegacy(parsedLyricsa)
- adapter?.updateLyrics(lyricsLegacy)
- newView?.updateLyrics(null)
- } else {
- lyricsLegacy = parsedLyrics
- adapter?.updateLyrics(lyricsLegacy)
- newView?.updateLyrics(null)
-
- }
- }
-
@SuppressLint("MissingPermission", "NotificationPermission") // only used on S/S_V2
override fun onForegroundServiceStartNotAllowedException() {
Log.w(TAG, "Failed to resume playback :/")
diff --git a/app/src/main/kotlin/org/akanework/gramophone/ui/fragments/settings/ExperimentalSettingsTopFragment.kt b/app/src/main/kotlin/org/akanework/gramophone/ui/fragments/settings/ExperimentalSettingsTopFragment.kt
index 574983807..47f47360a 100644
--- a/app/src/main/kotlin/org/akanework/gramophone/ui/fragments/settings/ExperimentalSettingsTopFragment.kt
+++ b/app/src/main/kotlin/org/akanework/gramophone/ui/fragments/settings/ExperimentalSettingsTopFragment.kt
@@ -17,22 +17,8 @@
package org.akanework.gramophone.ui.fragments.settings
-import android.Manifest
-import android.content.Intent
-import android.content.SharedPreferences
-import android.content.pm.PackageManager
-import android.net.Uri
-import android.os.Build
import android.os.Bundle
-import android.provider.Settings
-import android.util.Log
-import android.widget.Toast
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AlertDialog
-import androidx.core.app.ActivityCompat
import androidx.preference.Preference
-import androidx.preference.PreferenceManager
-import androidx.preference.SwitchPreferenceCompat
import org.akanework.gramophone.BuildConfig
import org.akanework.gramophone.R
import org.akanework.gramophone.ui.fragments.BasePreferenceFragment
@@ -44,28 +30,12 @@ class ExperimentalSettingsFragment : BaseSettingFragment(R.string.settings_exper
class ExperimentalSettingsTopFragment : BasePreferenceFragment() {
private lateinit var e: Exception
- private val prefs by lazy { PreferenceManager.getDefaultSharedPreferences(requireContext()) }
-
- // Activity Result API 注册权限请求
- private val requestPermissionLauncher = registerForActivityResult(
- ActivityResultContracts.RequestPermission()
- ) { isGranted: Boolean ->
- if (isGranted) {
- // 用户授予权限,启用状态栏歌词功能
- enableStatusBarLyric()
- } else {
- // 用户拒绝权限,显示提示
- Toast.makeText(requireContext(), "未授予通知权限,无法启用状态栏歌词", Toast.LENGTH_LONG).show()
- disableLyricUISetting()
- }
- }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.settings_experimental, rootKey)
findPreference("crash")!!.isVisible = BuildConfig.DEBUG
if (BuildConfig.DEBUG)
e = RuntimeException("skill issue")
- prefs.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
@@ -73,73 +43,5 @@ class ExperimentalSettingsTopFragment : BasePreferenceFragment() {
throw IllegalArgumentException("I crashed your app >:)", e)
}
return super.onPreferenceTreeClick(preference)
- if (preference.key == "enable_status_bar_lyric") {
- // 检查权限状态并请求权限
- checkAndRequestNotificationPermission()
- return true
- }
- }
-
- private fun checkAndRequestNotificationPermission() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- when {
- ActivityCompat.checkSelfPermission(
- requireContext(),
- Manifest.permission.POST_NOTIFICATIONS
- ) == PackageManager.PERMISSION_GRANTED -> {
- enableStatusBarLyric()
- }
- shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
- // 如果用户之前拒绝了权限请求但没有选择“永不提醒”
- requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
- }
- else -> {
- // 用户选择“永不提醒”,显示提示并关闭开关
- prefs.edit().putBoolean("lyric_statusbarLyric", false).apply()
- showPermissionDeniedMessageWithSettings()
- }
- }
- } else {
- enableStatusBarLyric()
- }
- }
-
- private val preferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
- if (key == "lyric_statusbarLyric") {
- val isLyricUIEnabled = prefs.getBoolean("lyric_statusbarLyric", true)
- if (isLyricUIEnabled) {
- checkAndRequestNotificationPermission()
- } else {
- disableLyricUISetting()
- }
- }
- }
-
- private fun disableLyricUISetting() {
- // 更新开关状态并通知UI
- prefs.edit().putBoolean("lyric_statusbarLyric", false).apply()
- findPreference("lyric_statusbarLyric")?.isChecked = false
- Toast.makeText(requireContext(),getString(R.string.settings_lyrics_StatusBarLyric_disable), Toast.LENGTH_SHORT).show()
- }
-
- private fun enableStatusBarLyric() {
- // 启用状态栏歌词的提示
- // 发送歌词的地方有单独判断
- Toast.makeText(requireContext(),getString(R.string.settings_lyrics_StatusBarLyric_enabled), Toast.LENGTH_SHORT).show()
- }
-
- private fun showPermissionDeniedMessageWithSettings() {
- AlertDialog.Builder(requireContext())
- .setTitle(getString(R.string.settings_lyrics_StatusBarLyric_permission_denied))
- .setMessage(getString(R.string.settings_lyrics_StatusBarLyric_open_permissions))
- .setPositiveButton(getString(R.string.settings_go_to_the_settings)) { _, _ ->
- // 跳转到应用的权限设置页面
- val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
- data = Uri.fromParts("package", requireContext().packageName, null)
- }
- startActivity(intent)
- }
- .setNegativeButton(getString(R.string.settings_cancel), null)
- .show()
}
}
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index ade0413fe..87a12ded5 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -168,12 +168,4 @@
主屏幕
配置标签顺序
应用将在启动时显示第一个标签。分隔符后的标签将被隐藏。
- 状态栏歌词
- 打开 状态栏歌词 (某些系统可用,需打开通知)
- 没有通知权限
- 启用状态栏歌词功能需要通知权限。请在系统设置中手动启用该权限。
- 状态栏歌词已打开
- 状态栏歌词已经关闭
- 去设置
- 取消
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8704cbb4f..63a6894b8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -198,12 +198,4 @@
Enable new lyric parser that supports word-by-word synchronisation, speaker indicator, offset and more
Enable new lyric UI
Experimental UI to display word-by-word lyric with advanced features
- Status Bar Lyric
- Enable StatusBarLyric (Available on some systems, requires notifications to be turned on)
- Notification permission denied
- Notification permission is required to enable the status bar lyrics feature. Please enable the permission manually in the system settings.
- Status bar lyrics enabled
- Status bar lyrics disable
- Go to the Settings
- Cancel
diff --git a/app/src/main/res/xml/settings_experimental.xml b/app/src/main/res/xml/settings_experimental.xml
index 3796f1706..981bef19e 100644
--- a/app/src/main/res/xml/settings_experimental.xml
+++ b/app/src/main/res/xml/settings_experimental.xml
@@ -58,17 +58,6 @@
android:widgetLayout="@layout/preference_switch_widget"
app:iconSpaceReserved="false" />
-
-
-
-
\ No newline at end of file