|
|
|
@ -1,10 +1,6 @@ |
|
|
|
package com.yunqiinnovation.music_service |
|
|
|
|
|
|
|
import android.app.Notification |
|
|
|
import android.app.NotificationChannel |
|
|
|
import android.app.NotificationManager |
|
|
|
import android.app.PendingIntent |
|
|
|
import android.app.Service |
|
|
|
import android.app.* |
|
|
|
import android.content.Context |
|
|
|
import android.content.Intent |
|
|
|
import android.media.AudioManager |
|
|
|
@ -13,8 +9,7 @@ import android.os.Build |
|
|
|
import android.os.IBinder |
|
|
|
import android.util.Log |
|
|
|
import androidx.core.app.NotificationCompat |
|
|
|
import com.yunqiinnovation.music_service.MusicServiceStarter |
|
|
|
import kotlinx.coroutines.CoroutineScope |
|
|
|
import com.yunqiinnovation.deepvoice_utils.FileLogger |
|
|
|
import java.util.concurrent.atomic.AtomicBoolean |
|
|
|
|
|
|
|
class MusicService : Service() { |
|
|
|
@ -23,131 +18,163 @@ class MusicService : Service() { |
|
|
|
private const val TAG = "MusicService" |
|
|
|
private const val CHANNEL_ID = "music_media_service_channel" |
|
|
|
private const val NOTIFICATION_ID = 1002 |
|
|
|
private const val PREF_NAME = "deep_voice_config" |
|
|
|
|
|
|
|
// 用于跟踪服务是否正在运行 |
|
|
|
private val isRunning = AtomicBoolean(false) |
|
|
|
|
|
|
|
// 获取服务运行状态 |
|
|
|
fun isServiceRunning(): Boolean = isRunning.get() |
|
|
|
} |
|
|
|
|
|
|
|
private var mediaPlayer: MediaPlayer? = null |
|
|
|
private val playlist = mutableListOf<String>() // 可扩展支持播放列表 |
|
|
|
private val playlist = mutableListOf<String>() // 可选:初始化为预置歌曲 |
|
|
|
private var currentIndex = 0 |
|
|
|
private var isPlaying = false |
|
|
|
|
|
|
|
override fun onCreate() { |
|
|
|
super.onCreate() |
|
|
|
val notification = createNotification() // 创建一个非空通知 |
|
|
|
startForeground(1, notification) |
|
|
|
} |
|
|
|
private var isPlaying = false |
|
|
|
/** |
|
|
|
* 创建前台服务通知 |
|
|
|
*/ |
|
|
|
private fun createNotification(): Notification { |
|
|
|
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
|
|
|
|
|
|
|
// Android 8.0+ 需要创建通知渠道 |
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
|
|
|
val channel = NotificationChannel( |
|
|
|
CHANNEL_ID, |
|
|
|
"音乐播放服务", |
|
|
|
NotificationManager.IMPORTANCE_LOW |
|
|
|
) |
|
|
|
manager.createNotificationChannel(channel) |
|
|
|
} |
|
|
|
|
|
|
|
// 点击通知打开主界面 |
|
|
|
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply { |
|
|
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP |
|
|
|
} |
|
|
|
val pendingIntent = if (intent != null) { |
|
|
|
PendingIntent.getActivity( |
|
|
|
this, |
|
|
|
0, |
|
|
|
intent, |
|
|
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT |
|
|
|
) |
|
|
|
} else { |
|
|
|
null |
|
|
|
} |
|
|
|
|
|
|
|
// 构建通知 |
|
|
|
val builder = NotificationCompat.Builder(this, CHANNEL_ID) |
|
|
|
.setContentTitle("DeepSound") |
|
|
|
.setContentText(if (isPlaying) "正在播放" else "已暂停") |
|
|
|
.setSmallIcon(android.R.drawable.ic_media_play) |
|
|
|
|
|
|
|
// 设置点击意图 |
|
|
|
pendingIntent?.let { builder.setContentIntent(it) } |
|
|
|
|
|
|
|
return builder.build() |
|
|
|
FileLogger.init(this) |
|
|
|
FileLogger.i(TAG, "MusicService 正在创建...") |
|
|
|
isRunning.set(true) |
|
|
|
Log.i(TAG, "MusicService Created") |
|
|
|
startForeground(NOTIFICATION_ID, createNotification("等待播放...")) |
|
|
|
isRunning.set(true) |
|
|
|
} |
|
|
|
|
|
|
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { |
|
|
|
val command = intent?.getStringExtra("command") ?: return START_NOT_STICKY |
|
|
|
Log.i(TAG, "onStartCommand: $command") |
|
|
|
|
|
|
|
when (command) { |
|
|
|
"play" -> { |
|
|
|
val url = intent.getStringExtra("url") ?: return START_NOT_STICKY |
|
|
|
if (!playlist.contains(url)) playlist.add(url) |
|
|
|
currentIndex = playlist.indexOf(url) |
|
|
|
play(url) |
|
|
|
} |
|
|
|
"pause" -> mediaPlayer?.pause() |
|
|
|
"resume" -> mediaPlayer?.start() |
|
|
|
"pause" -> pause() |
|
|
|
"resume" -> resume() |
|
|
|
"stop" -> stopSelf() |
|
|
|
"next" -> { |
|
|
|
currentIndex++ |
|
|
|
if (currentIndex < playlist.size) play(playlist[currentIndex]) |
|
|
|
if (currentIndex + 1 < playlist.size) { |
|
|
|
currentIndex++ |
|
|
|
play(playlist[currentIndex]) |
|
|
|
} |
|
|
|
} |
|
|
|
"previous" -> { |
|
|
|
currentIndex-- |
|
|
|
if (currentIndex >= 0) play(playlist[currentIndex]) |
|
|
|
if (currentIndex - 1 >= 0) { |
|
|
|
currentIndex-- |
|
|
|
play(playlist[currentIndex]) |
|
|
|
} |
|
|
|
} |
|
|
|
"setVolume" -> { |
|
|
|
val volume = intent.getFloatExtra("volume", 1.0f) |
|
|
|
val volume = intent.getFloatExtra("volume", 1.0f).coerceIn(0f, 1f) |
|
|
|
mediaPlayer?.setVolume(volume, volume) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return START_STICKY |
|
|
|
} |
|
|
|
|
|
|
|
private fun play(url: String) { |
|
|
|
Log.i(TAG, "开始播放音乐: $url") |
|
|
|
mediaPlayer?.release() |
|
|
|
Log.i(TAG, "播放音乐: $url") |
|
|
|
releaseMediaPlayer() |
|
|
|
|
|
|
|
mediaPlayer = MediaPlayer().apply { |
|
|
|
setDataSource(url) |
|
|
|
setAudioStreamType(AudioManager.STREAM_MUSIC) |
|
|
|
setOnPreparedListener { |
|
|
|
start() |
|
|
|
this@MusicService.isPlaying = true |
|
|
|
updateNotification("正在播放") |
|
|
|
Log.i(TAG, "开始播放") |
|
|
|
} |
|
|
|
setOnCompletionListener { |
|
|
|
Log.i(TAG, "播放完成") |
|
|
|
this@MusicService.isPlaying = false |
|
|
|
stopSelf() |
|
|
|
} |
|
|
|
setOnErrorListener { _, what, extra -> |
|
|
|
Log.e(TAG, "播放错误: what=$what extra=$extra") |
|
|
|
this@MusicService.isPlaying = false |
|
|
|
stopSelf() |
|
|
|
true |
|
|
|
} |
|
|
|
prepareAsync() |
|
|
|
setOnPreparedListener { start() } |
|
|
|
setOnCompletionListener { stopSelf() } |
|
|
|
} |
|
|
|
// startForeground(1, NotificationUtils.createNotification(this, "Playing...")) |
|
|
|
} |
|
|
|
|
|
|
|
private fun pause() { |
|
|
|
mediaPlayer?.let { |
|
|
|
if (it.isPlaying) { |
|
|
|
it.pause() |
|
|
|
this@MusicService.isPlaying = false |
|
|
|
updateNotification("已暂停") |
|
|
|
Log.i(TAG, "暂停播放") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun resume() { |
|
|
|
mediaPlayer?.let { |
|
|
|
if (!it.isPlaying) { |
|
|
|
it.start() |
|
|
|
this@MusicService.isPlaying = true |
|
|
|
updateNotification("继续播放") |
|
|
|
Log.i(TAG, "继续播放") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun releaseMediaPlayer() { |
|
|
|
mediaPlayer?.apply { |
|
|
|
stop() |
|
|
|
release() |
|
|
|
} |
|
|
|
mediaPlayer = null |
|
|
|
} |
|
|
|
|
|
|
|
private fun updateNotification(contentText: String) { |
|
|
|
val notification = createNotification(contentText) |
|
|
|
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
|
|
|
manager.notify(NOTIFICATION_ID, notification) |
|
|
|
} |
|
|
|
|
|
|
|
private fun createNotification(contentText: String): Notification { |
|
|
|
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
|
|
|
val channel = NotificationChannel( |
|
|
|
CHANNEL_ID, |
|
|
|
"音乐播放服务", |
|
|
|
NotificationManager.IMPORTANCE_LOW |
|
|
|
) |
|
|
|
manager.createNotificationChannel(channel) |
|
|
|
} |
|
|
|
|
|
|
|
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply { |
|
|
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP |
|
|
|
} |
|
|
|
val pendingIntent = intent?.let { |
|
|
|
PendingIntent.getActivity( |
|
|
|
this, 0, it, |
|
|
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
return NotificationCompat.Builder(this, CHANNEL_ID) |
|
|
|
.setContentTitle("DeepSound") |
|
|
|
.setContentText(contentText) |
|
|
|
.setSmallIcon(android.R.drawable.ic_media_play) |
|
|
|
.setContentIntent(pendingIntent) |
|
|
|
.setOngoing(true) |
|
|
|
.build() |
|
|
|
} |
|
|
|
|
|
|
|
override fun onDestroy() { |
|
|
|
mediaPlayer?.release() |
|
|
|
Log.i(TAG, "服务销毁,释放播放器") |
|
|
|
releaseMediaPlayer() |
|
|
|
stopForeground(true) |
|
|
|
isRunning.set(false) |
|
|
|
super.onDestroy() |
|
|
|
} |
|
|
|
|
|
|
|
override fun onBind(intent: Intent?): IBinder? = null |
|
|
|
|
|
|
|
/** |
|
|
|
* 释放资源 |
|
|
|
*/ |
|
|
|
fun release() { |
|
|
|
try { |
|
|
|
mediaPlayer?.apply { |
|
|
|
if (isPlaying) stop() |
|
|
|
release() |
|
|
|
} |
|
|
|
mediaPlayer = null |
|
|
|
} catch (e: Exception) { |
|
|
|
// 忽略异常 |
|
|
|
} |
|
|
|
} |
|
|
|
/** |
|
|
|
* 是否正在播放 |
|
|
|
*/ |
|
|
|
fun isPlaying() = mediaPlayer?.isPlaying == true |
|
|
|
} |
|
|
|
|