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? = nullval buf = ByteArray(2048)var len = 0var 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 = 0while (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.contentResolverval 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? = nullvar ous: BufferedOutputStream? = nullreturn try {ins = FileInputStream(tempFile)ous = BufferedOutputStream(FileOutputStream(destFile))var nread = 0Lval buf = ByteArray(1024)var n: Intwhile (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}}
相关文章:

Android 设置铃声和闹钟
Android设置铃声和闹钟使用的方法是一样的,但是要区别的去获取对应的权限。 统一权限,不管是设置闹钟还是铃声,他们都需要一个系统设置权限如下: //高版本需要WRITE_SETTINGS权限//此权限是敏感权限,无法动态申请,需要…...

自动化测试模型(一)
8.8.1 自动化测试模型概述 在自动化测试运用于测试工作的过程中,测试人员根据不同自动化测试工具、测试框架等所进行的测试活动进行了抽象,总结出线性测试、模块化驱动测试、数据驱动测试和关键字驱动测试这4种自动化测试模型。 线性测试 首先&#…...

解决nuxt3下载慢下载报错问题
在下载nuxt3时总是下不下来,最后还报错了。即使改成国内镜像源也不行。 解决方法: 直接去github上下载 https://github.com/nuxt/starter/tree/v3 解压后得到如下目录: 手动修改项目名和文件夹名 安装依赖 npm install可能会比较慢或下不…...
Ubuntu修改swap大小
查看swap位置和大小: swapon -s 方案一:修改原有文件大小方式 第一步:进入系统根目录cd /; 第二步:执行:sudo dd if/dev/zero of/swap bs1M count16384 //每段块1M 共16384块,即16G 第三步:执行…...

[C#] 复数乘法的跨平台SIMD硬件加速向量算法(不仅支持X86的Sse、Avx、Avx512,还支持Arm的AdvSimd)
文章目录 一、简单算法二、向量算法2.1 算法思路2.1.1 复数乘法的数学定义2.1.2 复数的数据布局2.1.3 第1步:计算 (a*c) (-b*d)i2.1.4 第2步:计算 (a*d) (b*c)i2.1.5 第3步:计算结果合并 2.2 算法实现(UseVectors)2.…...

C#WPF基础介绍/第一个WPF程序
什么是WPF WPF(Windows Presentation Foundation)是微软公司推出的一种用于创建窗口应用程序的界面框架。它是.NET Framework的一部分,提供了一套先进的用户界面设计工具和功能,可以实现丰富的图形、动画和多媒体效果。 WPF 使用…...

强大的接口测试可视化工具:Postman Flows
Postman Flows是一种接口测试可视化工具,可以使用流的形式在Postman工作台将请求接口、数据处理和创建实际流程整合到一起。如下图所示 Postman Flows是以API为中心的可视化应用程序开发界面。它提供了一个无限的画布用于编排和串连API,数据可视化来显示…...
系统设计及解决方案
发送验证码 1:根据手机号从Redis中获取value(验证码_时间戳) 2:如果value不为空,并且时间戳与当前时间戳的间隔小于60秒,则返回一个错误信息 3:生成随机验证码 4:调用阿里云短信服务API给用户发送短信验证码…...

从0入门自主空中机器人-2-2【无人机硬件选型-PX4篇】
1. 常用资料以及官方网站 无人机飞控PX4用户使用手册(无人机基本设置、地面站使用教程、软硬件搭建等):https://docs.px4.io/main/en/ PX4固件开源地址:https://github.com/PX4/PX4-Autopilot 飞控硬件、数传模块、GPS、分电板等…...

Linux之ARM(MX6U)裸机篇----2.汇编LED驱动实验
一,alpha的LED灯硬件原理分析 STM32 IO初始化流程 ①,使能GPIO时钟 ②,设置IO复用,复用为GPIO ③,配置GPIO的电气属性推挽,上拉下拉 ④,使用GPIO,输出高/低电平 MX6ULL IO初始化…...

e3 1220lv3 cpu-z分数
e3 1220lv3 双核四线程,1.1G频率,最低可在800MHZ运行,TDP 13W。 使用PE启动后测试cpu-z分数。 现在e3 1220lv3的价格落到69元。...
HTML5适配手机
要使 HTML5 网站适配手机设备,您可以遵循以下几个步骤和最佳实践: 1. 使用视口(Viewport) 在 HTML 文档的 <head> 部分添加视口元标签,以确保页面在移动设备上正确缩放和显示: <meta name"…...

C# 中使用 MassTransit
在生产环境中使用 MassTransit 时,通常需要进行详细的配置,包括设置连接字符串、配置队列、配置消费者、处理重试和错误队列等。以下是一个完整的示例,展示了如何在 ASP.NET Core 应用程序中配置 MassTransit,包括请求/响应模式和…...
网络编程 实现联网 b+Tree
网络编程是客户端和服务器之间通信的基础,也是现代应用开发中不可或缺的技能。在 Unity 中实现网络功能,需要结合计算机网络原理、数据结构与算法,以及网络协议的实际应用。以下是对这一块内容的详细介绍,包括每个涉及到的知识点&…...

zentao ubuntu上安装
#下载ZenTaoPMS-21.2-zbox_amd64.tar.gz(https://www.zentao.net/downloads.html) https://dl.zentao.net/zentao/21.2/ZenTaoPMS-21.2-zbox_amd64.tar.gzcd /opt tar -zxvf ZenTaoPMS-21.2-zbox_amd64.tar.gz#启动 /opt/zbox/zbox start /opt/zbox/zbox…...

Java 网络原理 ①-IO多路复用 || 自定义协议 || XML || JSON
这里是Themberfue 在学习完简单的网络编程后,我们将更加深入网络的学习——HTTP协议、TCP协议、UDP协议、IP协议........... IO多路复用 ✨在上一节基于 TCP 协议 编写应用层代码时,我们通过一个线程处理连接的申请,随后通过多线程或者线程…...
Bash Shell知识合集
1. chmod命令 创建一个bash shell脚本 hello.sh ~script $ touch hello.sh脚本创建完成后并不能直接执行,我们要用chmod命令授予它可执行的权限: ~script $ chmod 755 hello.sh授权后的脚本可以直接执行: ~script $ ./hello.sh2.指定运行…...
从0入门自主空中机器人-1【课程介绍】
关于本课程: 本次课程是一套面向对自主空中机器人感兴趣的学生、爱好者、相关从业人员的免费课程,包含了从硬件组装、机载电脑环境设置、代码部署、实机实验等全套详细流程,带你从0开始,组装属于自己的自主无人机,并让…...
Doris使用注意点
自己学习过程中整理,非官方 dws等最后用于查询的表可以考虑使用row存储加快查询,即用空间换时间duplicate key的选择要考虑最常查询使用适当使用bloomfilter 加速查询适当使用aggregate 模式降低max,avg,min之类的计算并加快查询…...

Mybatis插件better-mybatis-generator的下载与使用
1.下载 找到设置 插件 搜索better-mybatis-generator 下载并且重启IDEA 2.连接数据库 点击测试连接 连接成功如下图 3.使用插件 选择对应的表 右击选择 注意:mysql8.0驱动一定要勾上mysql_8 其他地方不要动 然后实体类 mapper xml就都生成好了 mapper里有默认增删…...
HarmonyOS5.0——CodeGenie:鸿蒙生态的AI编程革命
CodeGenie:鸿蒙生态的AI编程革命 华为推出的 CodeGenie 是集成于 DevEco Studio 的 AI 辅助编程工具,专为 HarmonyOS 应用开发设计。它通过深度优化 ArkTS 和 C 语言的代码生成能力,显著提升开发效率,降低鸿蒙生…...

技巧小结:根据寄存器手册写常用外设的驱动程序
需求:根据STM32F103寄存器手册写DMA模块的驱动程序 一、分析标准库函数的写法: 各个外设的寄存器地址定义在stm32f10x.h文件中:此文件由芯片厂家提供;内核的有关定义则定义在core_cm3.h文件中:ARM提供; 1、查看外设区域多级划分…...
cv::FileStorage用法
cv::FileStorage 是 OpenCV 中的一个类,用于读取和写入结构化数据(如 YAML、XML、JSON)。它非常适合保存和加载诸如: 相机内参(K、D) 位姿(R、T) IMU 数据 配置参数 向量、矩阵、…...

电脑商城--用户注册登录
用户注册 1 用户-创建数据表 1.使用use命令先选中store数据库。 USE store; 2.在store数据库中创建t_user用户数据表。 CREATE TABLE t_user (uid INT AUTO_INCREMENT COMMENT 用户id,username VARCHAR(20) NOT NULL UNIQUE COMMENT 用户名,password CHAR(32) NOT NULL COMME…...

美业破局:AI智能体如何用数据重塑战略决策(5/6)
摘要:文章深入剖析美业现状与挑战,指出其市场规模庞大但竞争激烈,面临获客难、成本高、服务标准化缺失等问题。随后阐述 AI 智能体与数据驱动决策的概念,强调其在美业管理中的重要性。接着详细说明 AI 智能体在美业数据收集、整理…...
react 常见的闭包陷阱深入解析
一、引子 先来看一段代码,你能说出这段代码的问题在哪吗? const [count, setCount] = useState(0); useEffect(() => {const timer = setTimeout(() => {setCount(count + 1);}, 1000);return () => clearTimeout(timer); }, []);正确答案: 这段代码存在闭包陷阱…...
若依添加添加监听容器配置(删除键,键过期)
1、配置Redis的键触发事件 # 基础配置 bind 0.0.0.0 # 允许所有IP连接 protected-mode no # 关闭保护模式(生产环境建议结合密码使用) port 6379 # 默认端口 daemonize no …...
测试(面经 八股)
目录 前言 一,软件测试(定义) 1,定义 2,目的 3,价值 4,实践 二,软件测试(目的) 1,找 bug 2,验证达标 3,质量评价…...

【深度学习新浪潮】如何入门三维重建?
入门三维重建算法技术需要结合数学基础、计算机视觉理论、编程实践和项目经验,以下是系统的学习路径和建议: 一、基础知识储备 1. 数学基础 线性代数:矩阵运算、向量空间、特征分解(用于相机矩阵、变换矩阵推导)。几何基础:三维几何(点、线、面的表示)、射影几何(单…...
Jetpack Compose 中,DisposableEffect、LaunchedEffect 和 sideEffect 区别和用途
在 Jetpack Compose 中,DisposableEffect、LaunchedEffect 和 sideEffect 都是用于处理副作用(Side Effects)的 API,但它们的用途和触发时机不同。以下是它们的核心概念和区别: 1. 副作用(Side Effect&…...