Android 使用 ToneGenerator 实现按键提示音

外部链接

DTMF原理
处理音频输出的变化
ToneGenerator API

简单效果

5_1698069103

功能简单实现

工具类

package com.xg.practise.util

import 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 = false

    fun initToneGenerator(context: Context) {
        runOnBackgroundThread(Runnable {
            //按键声音播放设置及初始化
            try {
                // 获取系统参数“按键操作音”是否开启
                mDTMFToneEnabled = Settings.System.getInt(
                    context.contentResolver,
                    Settings.System.DTMF_TONE_WHEN_DIALING, 1
                ) == 1
                synchronized(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 = false
                mToneGenerator = null
            }
        })
    }

    fun playTone(context: Context, dtmf: Int) {
        if (dtmf < 0) {
            return
        }
        if (!mDTMFToneEnabled) {
            return
        }
        val audioManager =
            context.applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        val ringerMode = audioManager.ringerMode
        if ((ringerMode == AudioManager.RINGER_MODE_SILENT
                    || ringerMode == AudioManager.RINGER_MODE_VIBRATE)
        ) {
            // 静音或者震动时不发出声音
            return
        }
        synchronized(mToneGeneratorLock) {
            mToneGenerator?.startTone(dtmf, DTMF_DURATION_MS) //发出声音
        }
    }

    fun release() {
        try {
            mDTMFToneEnabled = false
            mToneGenerator?.stopTone()
            mToneGenerator?.release()
            mToneGenerator = null
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

线程池工具

package com.xg.practise.util

import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit

val 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.practise

import 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.ToneHelper

class ToneActivity : AppCompatActivity() {
    private var mToneHelper
            : ToneHelper? = null

    override 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_P
            else -> -1
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        mToneHelper?.release()
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val text: TextView = itemView.findViewById(android.R.id.text1)
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值