当前位置: 首页 > article >正文

Android 设置铃声和闹钟

Android设置铃声和闹钟使用的方法是一样的,但是要区别的去获取对应的权限。

统一权限,不管是设置闹钟还是铃声,他们都需要一个系统设置权限如下:

在这里插入图片描述
在这里插入图片描述

        //高版本需要WRITE_SETTINGS权限
        //此权限是敏感权限,无法动态申请,需要跳转到系统界面开启
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //判断是否已经开启权限
            if (!Settings.System.canWrite(mContext)) {
                //没有开启这里需要一个弹窗来提醒用户要去设置下这个权限
                //自己的demo可以忽略此步骤,应用商店权限申请前需要说明
                mBindView.tvTitle.post {
                    //这是我自己的权限说明弹窗,自己的定义即可
                    OpenWriteDialog.show(this.supportFragmentManager){
                        if (it){
                            //这一步是跳转到系统设置界面,跳转之后有个回调,判断是否已经开启,开启了继续处理下一步
                            val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
                            intent.data = Uri.parse("package:$packageName")
                            startActivityForResult(intent, PERMISSION_LOCAL_CODE)
                        }
                    }
                }
            } else {
                //开启了运行下一步
                todo()
            }
        } else {
            //低版本直接运行下一步
            todo()
        }
    @RequiresApi(Build.VERSION_CODES.M)
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        //回调判断code是否一致
        if (requestCode == PERMISSION_LOCAL_CODE){
            //判断是否已经开启
            if (Settings.System.canWrite(this)) {
                //开启了进行下一步
                todo()
            }
        }
    }
设置铃声或者闹钟前都要先进行上一步的权限判断才可以继续进行

设置闹钟

首先动态判断权限

Manifest.permission.SET_ALARM
Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.WRITE_EXTERNAL_STORAGE

然后调用代码即可

RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_ALARM, uri)

注意这里的uri是手机本地的铃声路径,大多数的需求是下载网络.mp3 铃声到本地,然后更新闹钟,这里注意下下载之后需要更新到媒体库才可以正常设置,否则设置出来可能是未知或者直接设置不成功----------如何下载更新到媒体库后面统一讲

设置铃声

同闹钟一样,首先需要动态获取权限

Manifest.permission.READ_EXTERNAL_STORAGE
Manifest.permission.WRITE_EXTERNAL_STORAGE

其次设置铃声即可

RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, uri)

这里的uri同闹钟一样,需要更新到媒体库才可以设置

下载网页铃声到本地

在这里插入图片描述

DownloadUtil.download("网页链接","存储路径", "文件名称.mp3",
                    object : DownloadUtil.OnDownloadListener{
                        override fun onDownloadSuccess(file: File?) {
                            //下载成功以及下载后的文件
                        }
                        override fun onDownloading(progress: Int) {
                            //下载进度
                        }
                        override fun onDownloadFailed(e: Exception?) {
                            //下载失败
                        }

                    })
存储路径地址这里给出建议写法
    private fun getUrlPath(): String {
        val externalFilesDir: File? = this.getExternalFilesDir("")
        val customFile = File(externalFilesDir!!.absolutePath, "Sandbox")
        if (!customFile.exists()) {
            customFile.mkdirs()
        }
        return customFile.absolutePath + File.separator
    }
文件名称后缀 .mp3即可

DownloadUtil源码

object DownloadUtil {

    private var okHttpClient: OkHttpClient? = null

    /**
     * @param url          下载连接
     * @param destFileDir  下载的文件储存目录
     * @param destFileName 下载文件名称
     * @param listener     下载监听
     */
    fun download(url: String, destFileDir: String, destFileName: String, listener: OnDownloadListener) {
        if (url == null || url == ""){
            return
        }
        if (okHttpClient == null){
            okHttpClient = OkHttpClient()
        }
        val request: Request = Request.Builder().url(url).build()
        okHttpClient!!.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                // 下载失败监听回调
                listener.onDownloadFailed(e)
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                if (response.body != null) {
                    var inputStream: InputStream? = null
                    val buf = ByteArray(2048)
                    var len = 0
                    var fos: FileOutputStream? = null
                    // 储存下载文件的目录
                    val dir = File(destFileDir)
                    if (!dir.exists()) {
                        dir.mkdirs()
                    }
                    val file = File(dir, destFileName)
                    try {
                        inputStream = response.body!!.byteStream()
                        val total: Long = response.body!!.contentLength()
                        fos = FileOutputStream(file)
                        var sum: Long = 0
                        while (inputStream.read(buf).also { len = it } != -1) {
                            fos.write(buf, 0, len)
                            sum += len.toLong()
                            val progress = (sum * 1.0f / total * 100).toInt()
                            // 下载中更新进度条
                            listener.onDownloading(progress)
                        }
                        fos.flush()
                        // 下载完成
                        listener.onDownloadSuccess(file)
                    } catch (e: Exception) {
                        listener.onDownloadFailed(e)
                    } finally {
                        try {
                            inputStream?.close()
                        } catch (e: IOException) {
                            listener.onDownloadFailed(e)
                        }
                        try {
                            fos?.close()
                        } catch (e: IOException) {
                            listener.onDownloadFailed(e)
                        }
                    }
                }else{
                    listener.onDownloadFailed(IOException("接口失败"))
                }
            }
        })
    }

    interface OnDownloadListener {
        /**
         * @param file 下载成功后的文件
         */
        fun onDownloadSuccess(file: File?)

        /**
         * @param progress 下载进度
         */
        fun onDownloading(progress: Int)

        /**
         * @param e 下载异常信息
         */
        fun onDownloadFailed(e: Exception?)
    }

}

此时就将网络音频下载到本地了,这时候拿到file是无法更新到闹钟或者铃声的,甚至本地音乐里面都找不它,需要更新到媒体库才可以进行设置

更新到媒体库

更新媒体库使用的是 ContentValues 以前文章写过下载视频到本地,都是一样的,只不过参数不同

在这里插入图片描述
在这里插入图片描述

可以看下参数对比下

更新到媒体库的时候要注意 高版本和低版本区分更新

如果你此时使用的是网上大多数的 MediaScannerConnection.scanFile() 方法,大概率是不会成功的

使用
DangUtils.setMYRingtone(mContext,mDownFile!!.absolutePath,mDownType,mDownName);

其中 mDownFile 就是我下载到本地的文件

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

DangUtils 代码

object DangUtils {

    /**
     * 将资源更新到媒体库
     * context - 上下文
     * filePath - 本地路径
     * type - 类型-设置闹钟还是铃声
     * name - 名称,提示用户的 可有可无
     */
    fun setMYRingtone(context: Context, filePath: String?,type: String,name: String): Boolean {
        if (filePath == null || filePath == ""){
            return false
        }
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            saveVideoToAlbumBeforeQ(context, filePath,type,name)
        } else {
            saveVideoToAlbumAfterQ(context, filePath,type,name)
        }
    }

    private fun saveVideoToAlbumAfterQ(context: Context, filePath: String,mDownType: String,name: String): Boolean {
        return try {
            val contentResolver = context.contentResolver
            val tempFile = File(filePath)
            val contentValues = getVideoContentValues(context, tempFile, System.currentTimeMillis())
            val uri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)
            copyFileAfterQ(context, contentResolver, tempFile, uri)
            contentValues.clear()
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
            context.contentResolver.update(uri!!, contentValues, null, null)
            context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))

            if (mDownType == Setting_LS) {
                // 设置系统来电铃声
                RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, uri)
                Toast.makeText(context, "已将${name}设置为来电铃声", Toast.LENGTH_SHORT).show()
            }else{
                RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_ALARM, uri)
                Toast.makeText(context, "已将${name}设置为闹铃", Toast.LENGTH_SHORT).show()
            }

            true
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            if (mDownType == Setting_LS) {
                Toast.makeText(context, "铃声设置失败", Toast.LENGTH_SHORT).show()
            }else{
                Toast.makeText(context, "闹铃设置失败", Toast.LENGTH_SHORT).show()
            }
            false
        }
    }

    private fun saveVideoToAlbumBeforeQ(context: Context, videoFile: String,mDownType: String,name: String): Boolean {
        val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
        val tempFile = File(videoFile)
        val destFile = File(picDir, context.packageName + File.separator + tempFile.name)
        var ins: FileInputStream? = null
        var ous: BufferedOutputStream? = null
        return try {
            ins = FileInputStream(tempFile)
            ous = BufferedOutputStream(FileOutputStream(destFile))
            var nread = 0L
            val buf = ByteArray(1024)
            var n: Int
            while (ins.read(buf).also { n = it } > 0) {
                ous.write(buf, 0, n)
                nread += n.toLong()
            }
            MediaScannerConnection.scanFile(
                context, arrayOf(destFile.absolutePath),null
            ) { path: String?, uri: Uri? ->
                if (mDownType == Setting_LS) {
                    // 设置系统来电铃声
                    RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, uri)
                    Toast.makeText(context, "已将${name}设置为来电铃声", Toast.LENGTH_SHORT).show()
                }else{
                    RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_ALARM, uri)
                    Toast.makeText(context, "已将${name}设置为闹铃", Toast.LENGTH_SHORT).show()
                }
            }
            true
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            if (mDownType == Setting_LS) {
                Toast.makeText(context, "铃声设置失败", Toast.LENGTH_SHORT).show()
            }else{
                Toast.makeText(context, "闹铃设置失败", Toast.LENGTH_SHORT).show()
            }
            false
        } finally {
            try {
                ins?.close()
                ous?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    @Throws(IOException::class)
    private fun copyFileAfterQ(
        context: Context,
        localContentResolver: ContentResolver,
        tempFile: File,
        localUri: Uri?
    ) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
            context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q
        ) {
            //拷贝文件到相册的uri,android10及以上得这么干,否则不会显示。可以参考ScreenMediaRecorder的save方法
            val os = localContentResolver.openOutputStream(localUri!!)
            Files.copy(tempFile.toPath(), os)
            os!!.close()
            tempFile.delete()
        }
    }


    /**
     * 获取视频的contentValue
     */
    private fun getVideoContentValues(context: Context, paramFile: File, timestamp: Long): ContentValues {
        val localContentValues = ContentValues()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            localContentValues.put(
                MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC
                        + File.separator + context.packageName
            )
        }
        localContentValues.put(MediaStore.Audio.Media.TITLE, paramFile.name)
        localContentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, paramFile.name)
        localContentValues.put(MediaStore.Audio.Media.MIME_TYPE, "music/mp3")
        localContentValues.put(MediaStore.Audio.Media.DATE_TAKEN, timestamp)
        localContentValues.put(MediaStore.Audio.Media.DATE_MODIFIED, timestamp)
        localContentValues.put(MediaStore.Audio.Media.DATE_ADDED, timestamp)
        localContentValues.put(MediaStore.Audio.Media.SIZE, paramFile.length())
        return localContentValues
    }

}

http://www.kler.cn/a/458517.html

相关文章:

  • Docker--Kibana
  • MYSQL如何重置root密码
  • MYSQL使用角色
  • wx006基于springboot+vue+uniapp的电器维修系统小程序
  • uniapp下载打开实现方案,支持安卓ios和h5,下载文件到指定目录,安卓文件管理内可查看到
  • termux-boot安卓开机自动启动应用
  • Colyseus的room.onStateChange重复触发问题
  • Redis 集群架构:高可用与扩展性
  • 苍穹外卖day07缓存部分分析
  • 深入理解 Docker 网桥配置与网络管理
  • C#编写的金鱼趣味小应用 - 开源研究系列文章
  • 博通收购VMware后,新旧VMware兼容性列表查询方案对比
  • 未来网络技术的新征程:5G、物联网与边缘计算(10/10)
  • 【小程序】wxss与rpx单位以及全局样式和局部样式
  • PG备份恢复--pg_dump
  • SpringBoot -- Docker Compose的支持
  • RK356x bsp 7 - PCF8563 RTC调试记录
  • Unity 读Excel,读取xlsx文件解决方案
  • 【Rabbitmq篇】高级特性----事务,消息分发
  • 【每日学点鸿蒙知识】Web跳转系统应用、页面动态跳转、非UI中观测变化、MVVM模式、循环中使用定时问题