Android 使用 ToneGenerator 实现按键提示音
- 外部链接
- 简单效果
- 功能简单实现
- 工具类
- 线程池工具
- 主页面简单实现
外部链接
DTMF原理
处理音频输出的变化
ToneGenerator API
简单效果
功能简单实现
工具类
package com.xg.practise.utilimport android.app.Activity
import android.content.Context
import android.media.AudioManager
import android.media.ToneGenerator
import android.provider.Settings//Tone 相关
const val DTMF_DURATION_MS = 120 // 声音的播放时间,毫秒class ToneHelper() {// 监视器对象锁private val mToneGeneratorLock = Any()// 声音产生器private var mToneGenerator: ToneGenerator? = null// 系统参数“按键操作音”标志位private var mDTMFToneEnabled = falsefun initToneGenerator(context: Context) {runOnBackgroundThread(Runnable {//按键声音播放设置及初始化try {// 获取系统参数“按键操作音”是否开启mDTMFToneEnabled = Settings.System.getInt(context.contentResolver,Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1synchronized(mToneGeneratorLock) {if (mDTMFToneEnabled && mToneGenerator == null) {mToneGenerator = ToneGenerator(AudioManager.STREAM_DTMF, 100) // 设置声音的大小if (context is Activity) {context.volumeControlStream = AudioManager.STREAM_DTMF}}}} catch (e: Exception) {e.printStackTrace()mDTMFToneEnabled = falsemToneGenerator = null}})}fun playTone(context: Context, dtmf: Int) {if (dtmf < 0) {return}if (!mDTMFToneEnabled) {return}val audioManager =context.applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManagerval ringerMode = audioManager.ringerModeif ((ringerMode == AudioManager.RINGER_MODE_SILENT|| ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {// 静音或者震动时不发出声音return}synchronized(mToneGeneratorLock) {mToneGenerator?.startTone(dtmf, DTMF_DURATION_MS) //发出声音}}fun release() {try {mDTMFToneEnabled = falsemToneGenerator?.stopTone()mToneGenerator?.release()mToneGenerator = null} catch (e: Exception) {e.printStackTrace()}}
}
线程池工具
package com.xg.practise.utilimport java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnitval executor: ScheduledExecutorService = Executors.newScheduledThreadPool(10)fun runOnBackgroundThread(runnable: Runnable?) {executor.execute(runnable)
}fun runOnBackgroundThread(runnable: Runnable?, delay: Long) {executor.schedule(runnable, delay, TimeUnit.MILLISECONDS)
}
主页面简单实现
package com.xg.practiseimport android.media.ToneGenerator
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.xg.practise.databinding.ActivityToneBinding
import com.xg.practise.util.ToneHelperclass ToneActivity : AppCompatActivity() {private var mToneHelper: ToneHelper? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)var dataBinding =DataBindingUtil.setContentView<ActivityToneBinding>(this, R.layout.activity_tone);setContentView(dataBinding.root)mToneHelper = ToneHelper()mToneHelper?.initToneGenerator(this@ToneActivity)var array = arrayOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#")dataBinding.recycler.layoutManager = GridLayoutManager(this@ToneActivity, 3)dataBinding.recycler.adapter = object : RecyclerView.Adapter<MyViewHolder>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {return MyViewHolder(LayoutInflater.from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false))}override fun getItemCount(): Int {return array.size}override fun onBindViewHolder(holder: MyViewHolder, position: Int) {holder.text.text = array[position]holder.text.setOnClickListener {mToneHelper?.playTone(holder.text.context,convertToneDtmf(array[position]))}}}}fun convertToneDtmf(key: String?): Int {return when (key) {"0" -> ToneGenerator.TONE_DTMF_0"1" -> ToneGenerator.TONE_DTMF_1"2" -> ToneGenerator.TONE_DTMF_2"3" -> ToneGenerator.TONE_DTMF_3"4" -> ToneGenerator.TONE_DTMF_4"5" -> ToneGenerator.TONE_DTMF_5"6" -> ToneGenerator.TONE_DTMF_6"7" -> ToneGenerator.TONE_DTMF_7"8" -> ToneGenerator.TONE_DTMF_8"9" -> ToneGenerator.TONE_DTMF_9"*" -> ToneGenerator.TONE_DTMF_S"#" -> ToneGenerator.TONE_DTMF_Pelse -> -1}}override fun onDestroy() {super.onDestroy()mToneHelper?.release()}class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {val text: TextView = itemView.findViewById(android.R.id.text1)}
}