Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Add support StatusBarLyric" #309

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<uses-feature android:name="android.hardware.faketouch" android:required="false"/>

<!-- Read music files (Android 13 and later) (includes .lrc and thumbnails) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"
android:minSdkVersion="33" />
<!-- Read cover files, this is never requested by UI but exists for users who want it -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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


Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<MediaStoreUtils.Lyric>?, 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 :/")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,102 +30,18 @@ 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<Preference>("crash")!!.isVisible = BuildConfig.DEBUG
if (BuildConfig.DEBUG)
e = RuntimeException("skill issue")
prefs.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
}

override fun onPreferenceTreeClick(preference: Preference): Boolean {
if (preference.key == "crash" && BuildConfig.DEBUG) {
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<SwitchPreferenceCompat>("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()
}
}
8 changes: 0 additions & 8 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,4 @@
<string name="settings_preference_category_home">主屏幕</string>
<string name="tab_order">配置标签顺序</string>
<string name="tab_order_summary">应用将在启动时显示第一个标签。分隔符后的标签将被隐藏。</string>
<string name="settings_lyrics_StatusBarLyric">状态栏歌词</string>
<string name="settings_lyrics_StatusBarLyric_summary">打开 状态栏歌词 (某些系统可用,需打开通知)</string>
<string name="settings_lyrics_StatusBarLyric_permission_denied">没有通知权限</string>
<string name="settings_lyrics_StatusBarLyric_open_permissions">启用状态栏歌词功能需要通知权限。请在系统设置中手动启用该权限。</string>
<string name="settings_lyrics_StatusBarLyric_enabled">状态栏歌词已打开</string>
<string name="settings_lyrics_StatusBarLyric_disable">状态栏歌词已经关闭</string>
<string name="settings_go_to_the_settings">去设置</string>
<string name="settings_cancel">取消</string>
</resources>
8 changes: 0 additions & 8 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,4 @@
<string name="settings_lyrics_parser_summary">Enable new lyric parser that supports word-by-word synchronisation, speaker indicator, offset and more</string>
<string name="settings_lyrics_ui">Enable new lyric UI</string>
<string name="settings_lyrics_ui_summary">Experimental UI to display word-by-word lyric with advanced features</string>
<string name="settings_lyrics_StatusBarLyric">Status Bar Lyric </string>
<string name="settings_lyrics_StatusBarLyric_summary">Enable StatusBarLyric (Available on some systems, requires notifications to be turned on)</string>
<string name="settings_lyrics_StatusBarLyric_permission_denied">Notification permission denied</string>
<string name="settings_lyrics_StatusBarLyric_open_permissions">Notification permission is required to enable the status bar lyrics feature. Please enable the permission manually in the system settings.</string>
<string name="settings_lyrics_StatusBarLyric_enabled">Status bar lyrics enabled</string>
<string name="settings_lyrics_StatusBarLyric_disable">Status bar lyrics disable</string>
<string name="settings_go_to_the_settings">Go to the Settings</string>
<string name="settings_cancel">Cancel</string>
</resources>
11 changes: 0 additions & 11 deletions app/src/main/res/xml/settings_experimental.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,6 @@
android:widgetLayout="@layout/preference_switch_widget"
app:iconSpaceReserved="false" />

<SwitchPreferenceCompat
android:defaultValue="false"
android:key="lyric_statusbarLyric"
android:layout="@layout/preference_switch"
android:title="@string/settings_lyrics_StatusBarLyric"
android:summary="@string/settings_lyrics_StatusBarLyric_summary"
android:widgetLayout="@layout/preference_switch_widget"
app:iconSpaceReserved="false" />


</PreferenceCategory>


</PreferenceScreen>