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
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/942623.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

三维扫描在汽车/航空行业应用

三维扫描技术应用范围广泛&#xff0c;从小型精密零件到大型工业设备&#xff0c;都能实现快速、准确的测量。 通过先进三维扫描技术获取产品和物体的形面三维数据&#xff0c;建立实物的三维图档&#xff0c;满足各种实物3D模型数据获取、三维数字化展示、3D多媒体开发、三维…

optuna和 lightgbm

文章目录 optuna使用1.导入相关包2.定义模型可选参数3.定义训练代码和评估代码4.定义目标函数5.运行程序6.可视化7.超参数的重要性8.查看相关信息9.可视化的一个完整示例10.lightgbm实验 optuna使用 1.导入相关包 import torch import torch.nn as nn import torch.nn.functi…

【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?

文章目录 前言问题描述问题分析问题解决1.允许所有用户上传驱动文件2.如果是想只上传白名单的驱动 前言 该方法适合永洪BI系列产品&#xff0c;包括不限于vividime desktop&#xff0c;vividime z-suit&#xff0c;vividime x-suit产品。 问题描述 当我们连接数据源的时候&a…

[项目][boost搜索引擎#4] cpp-httplib使用 log.hpp 前端 测试及总结

目录 编写http_server模块 1. 引入cpp-httplib到项目中 2. cpp-httplib的使用介绍 3. 正式编写http_server 九、添加日志到项目中 十、编写前端模块 十一. 详解传 gitee 十二、项目总结 项目的扩展 写在前面 [项目详解][boost搜索引擎#1] 概述 | 去标签 | 数据清洗 |…

项目练习:若依系统的svg-icon功能实现

文章目录 一、svg图片准备二、自定义Svg组件三、svg插件开发四、Svg组件使用 一、svg图片准备 src/assets/icons/svg 其中svg目录里&#xff0c;存放了所需要的图片 index.js import Vue from vue import SvgIcon from /components/SvgIcon// svg component// register glob…

水库大坝三维模型的开发和使用3Dmax篇

成果图 开发过程 工具插件three.js先加载模型做水体衔接水位测量标尺水位标记断面标记大坝监测点打点 上代码&#xff0c;技术交流V: bloxed <template><div class"box w100 h100"><el-row :gutter"20" v-loading"loading"e…

Win10提示“缺少fbgemm.dll”怎么办?缺失fbgemm.dll文件的修复方法来啦!

fbgemm.dll文件的作用 fbgemm.dll&#xff08;Facebook GEMM library&#xff09;是一个动态链接库文件&#xff0c;它主要用于优化矩阵乘法运算&#xff0c;提高计算性能。虽然它不是Windows 10系统的核心组件&#xff0c;但在某些应用程序或游戏中&#xff0c;尤其是那些需要…

Petalinux使用QSPI FLASH引导启动

目录 1. 预分配Flash空间 1.1 大小估计 1.2 其他注意事项 2. 配置Flash分区 3. 配置各主要文件在Flash中的地址范围 4. 配置boot.scr的偏移 5. 修改U-Boot环境变量在Flash的偏移量 6. 配置设备树中的Flash 7. 开启对EXT4分区管理的支持(根据需要) 8. 编译u-boot 9.…

Android——自定义按钮button

项目中经常高频使用按钮&#xff0c;要求&#xff1a;可设置颜色&#xff0c;有圆角且有按下效果的Button 一、自定义按钮button button的代码为 package com.fslihua.clickeffectimport android.annotation.SuppressLint import android.content.Context import android.gra…

黑龙江等保测评费用怎么收?

‌黑龙江二级等保测评费用‌&#xff1a;费用区间大致在3万至6万人民币之间&#xff0c;具体费用取决于测评机构的定价策略、所提供的服务内容以及企业的实际需求‌&#xff0c;服务内容包括防火墙、Web应用防火墙(WAF)、堡垒机、日志审计、漏洞扫描以及等保安全整改等‌。 ‌…

中文拼写检测纠正 Read, Listen, and See Leveraging Multimodal Information 论文

拼写纠正系列 NLP 中文拼写检测实现思路 NLP 中文拼写检测纠正算法整理 NLP 英文拼写算法&#xff0c;如果提升 100W 倍的性能&#xff1f; NLP 中文拼写检测纠正 Paper java 实现中英文拼写检查和错误纠正&#xff1f;可我只会写 CRUD 啊&#xff01; 一个提升英文单词拼…

vue2 elementui if导致的rules判断失效

优化目标 和 目标转化出价必填的 切换的时候还会隐藏掉 这时候的if语句会导致rules判断失效 我的办法是把判断拉到外面 别放在el-form-item里 <section v-if"unitForm.baseTarget OCPM && unitForm.cpaTargetOptions ! undefined && unitForm.cpaTa…

前端(Ajax)

1.客户端请求 向https://jsonplaceholder.typicode.com/users发送get请求 const xhr new XMLHttpRequest(); console.log(xhr.readyState); xhr.open(‘get’, ‘https://jsonplaceholder.typicode.com/users’) console.log(xhr.readyState); xhr.send(); console.log(xhr.…

uboot, s5pv210 , main_loop 分析(16)

main_loop 的代码如下&#xff1a; 4443 void main_loop (void)42 {41 #ifndef CONFIG_SYS_HUSH_PARSER E 40 ▎ static char lastcommand[CONFIG_SYS_CBSIZE] { 0, }; ■ Use of undeclared identifier CONFIG_SYS_CBSIZE39 ▎ int len;38 ▎ int rc 1;37 ▎ …

信号强劲,通信清晰:北斗三号多模对讲机TD70——专业通信解决方案

在边防海防等国家安全的关键领域&#xff0c;通信的稳定性和可靠性关乎着任务的成败和战士们的安全。北斗三号多模对讲机TD70&#xff0c;凭借其卓越的性能和全面的功能&#xff0c;成为了边防海防通信的利器&#xff0c;守护着国家安全的前沿哨兵。 一、三网融合&#xff0c;…

Arduino驱动DS18B20测量环境温度

DS18B20是一款高精度的单总线数字温度传感器&#xff0c;具体参数如下表所示&#xff1a; 参数名称 参数特性 测温范围 -55~125℃ 测量精度 在-10~85℃范围内的误差为0.5℃ 分辨率 9~12位数字信号&#xff0c;分辨率分别为0.5℃、0.25℃、0.125℃和0.0625℃ 通信方式 …

vector快慢指针+例题详解

1.快慢指针 例题 给定一个链表&#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;我们使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;索引从…

C++--------效率和表示

C 效率和表示 效率 时间效率&#xff1a;在 C 中&#xff0c;不同的数据结构和算法有着各异的时间复杂度。例如&#xff0c;访问数组元素的时间复杂度是 O ( 1 ) O(1) O(1)&#xff0c;而遍历链表查找元素的时间复杂度最坏情况下是 O ( n ) O(n) O(n)。选择合适的算法与数据…

【Mac】终端改色-让用户名和主机名有颜色

效果图 配置zsh 1.打开终端&#xff0c;进入.zshrc配置 cd ~ vim .zshrc2.添加如下配置并保存 # 启用命令行颜色显示 export CLICOLOR1 ## 加载颜色支持 autoload -U colors && colors # 配置 zsh 提示符 PROMPT"%{$fg_bold[red]%}%n%{$reset_color%}%{$fg_bol…

模拟——郑益慧_笔记1_绪论

B站视频链接 模电是数电的基础&#xff1b;参考书&#xff1a; 模拟电子技术基础&#xff08;第四版&#xff09;华成英、童诗白主编&#xff0c;高等教育出版社&#xff1b;电子技术基础 模拟部分 康华光主编&#xff0c;高等教育出版社&#xff1b; 电子技术的发展史 电子…