4 changed files with 175 additions and 7 deletions
@ -0,0 +1,125 @@ |
|||||
|
package com.yunqiinnovation.azure_speech.tools |
||||
|
|
||||
|
import android.app.Notification |
||||
|
import android.app.NotificationChannel |
||||
|
import android.app.NotificationManager |
||||
|
import android.app.PendingIntent |
||||
|
import android.app.Service |
||||
|
import android.content.Context |
||||
|
import android.content.Intent |
||||
|
import android.os.Build |
||||
|
import android.os.IBinder |
||||
|
import androidx.core.app.NotificationCompat |
||||
|
import android.util.Log |
||||
|
|
||||
|
/** |
||||
|
* 音频录制前台服务 |
||||
|
* 用于在录制音频时保持应用在前台运行,防止系统杀死应用 |
||||
|
*/ |
||||
|
class AudioRecordingForegroundService : Service() { |
||||
|
|
||||
|
companion object { |
||||
|
private const val TAG = "AudioRecordingService" |
||||
|
private const val NOTIFICATION_ID = 1001 |
||||
|
private const val CHANNEL_ID = "audio_recording_channel" |
||||
|
private const val CHANNEL_NAME = "音频录制服务" |
||||
|
|
||||
|
/** |
||||
|
* 启动前台服务 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
fun startService(context: Context) { |
||||
|
val intent = Intent(context, AudioRecordingForegroundService::class.java) |
||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||
|
context.startForegroundService(intent) |
||||
|
} else { |
||||
|
context.startService(intent) |
||||
|
} |
||||
|
Log.d(TAG, "音频录制前台服务已启动") |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 停止前台服务 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
fun stopService(context: Context) { |
||||
|
val intent = Intent(context, AudioRecordingForegroundService::class.java) |
||||
|
context.stopService(intent) |
||||
|
Log.d(TAG, "音频录制前台服务已停止") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
override fun onCreate() { |
||||
|
super.onCreate() |
||||
|
Log.d(TAG, "AudioRecordingForegroundService onCreate") |
||||
|
createNotificationChannel() |
||||
|
} |
||||
|
|
||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { |
||||
|
Log.d(TAG, "AudioRecordingForegroundService onStartCommand") |
||||
|
|
||||
|
// 创建前台通知 |
||||
|
val notification = createNotification() |
||||
|
startForeground(NOTIFICATION_ID, notification) |
||||
|
|
||||
|
// 返回START_STICKY确保服务被系统杀死后会重启 |
||||
|
return START_STICKY |
||||
|
} |
||||
|
|
||||
|
override fun onBind(intent: Intent?): IBinder? { |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
override fun onDestroy() { |
||||
|
super.onDestroy() |
||||
|
Log.d(TAG, "AudioRecordingForegroundService onDestroy") |
||||
|
stopForeground(true) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建通知渠道(Android 8.0及以上需要) |
||||
|
*/ |
||||
|
private fun createNotificationChannel() { |
||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||
|
val channel = NotificationChannel( |
||||
|
CHANNEL_ID, |
||||
|
CHANNEL_NAME, |
||||
|
NotificationManager.IMPORTANCE_LOW |
||||
|
).apply { |
||||
|
description = "用于音频录制时保持应用运行" |
||||
|
setShowBadge(false) |
||||
|
setSound(null, null) |
||||
|
enableVibration(false) |
||||
|
} |
||||
|
|
||||
|
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
||||
|
notificationManager.createNotificationChannel(channel) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建前台服务通知 |
||||
|
* @return 通知对象 |
||||
|
*/ |
||||
|
private fun createNotification(): Notification { |
||||
|
// 创建点击通知时的意图(可以打开应用主界面) |
||||
|
val intent = packageManager.getLaunchIntentForPackage(packageName) |
||||
|
val pendingIntent = PendingIntent.getActivity( |
||||
|
this, |
||||
|
0, |
||||
|
intent, |
||||
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE |
||||
|
) |
||||
|
|
||||
|
return NotificationCompat.Builder(this, CHANNEL_ID) |
||||
|
.setContentTitle("语音助手正在运行") |
||||
|
.setContentText("正在录制音频,点击返回应用") |
||||
|
.setSmallIcon(android.R.drawable.ic_btn_speak_now) // 使用系统默认麦克风图标 |
||||
|
.setContentIntent(pendingIntent) |
||||
|
.setOngoing(true) // 设置为持续通知,用户无法滑动删除 |
||||
|
.setPriority(NotificationCompat.PRIORITY_LOW) |
||||
|
.setCategory(NotificationCompat.CATEGORY_SERVICE) |
||||
|
.setShowWhen(false) |
||||
|
.build() |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue