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

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设置铃声和闹钟使用的方法是一样的&#xff0c;但是要区别的去获取对应的权限。 统一权限&#xff0c;不管是设置闹钟还是铃声&#xff0c;他们都需要一个系统设置权限如下: //高版本需要WRITE_SETTINGS权限//此权限是敏感权限&#xff0c;无法动态申请&#xff0c;需要…...

自动化测试模型(一)

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

解决nuxt3下载慢下载报错问题

在下载nuxt3时总是下不下来&#xff0c;最后还报错了。即使改成国内镜像源也不行。 解决方法&#xff1a; 直接去github上下载 https://github.com/nuxt/starter/tree/v3 解压后得到如下目录&#xff1a; 手动修改项目名和文件夹名 安装依赖 npm install可能会比较慢或下不…...

Ubuntu修改swap大小

查看swap位置和大小&#xff1a; swapon -s 方案一&#xff1a;修改原有文件大小方式 第一步&#xff1a;进入系统根目录cd /; 第二步&#xff1a;执行&#xff1a;sudo dd if/dev/zero of/swap bs1M count16384 //每段块1M 共16384块&#xff0c;即16G 第三步&#xff1a;执行…...

[C#] 复数乘法的跨平台SIMD硬件加速向量算法(不仅支持X86的Sse、Avx、Avx512,还支持Arm的AdvSimd)

文章目录 一、简单算法二、向量算法2.1 算法思路2.1.1 复数乘法的数学定义2.1.2 复数的数据布局2.1.3 第1步&#xff1a;计算 (a*c) (-b*d)i2.1.4 第2步&#xff1a;计算 (a*d) (b*c)i2.1.5 第3步&#xff1a;计算结果合并 2.2 算法实现&#xff08;UseVectors&#xff09;2.…...

C#WPF基础介绍/第一个WPF程序

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

强大的接口测试可视化工具:Postman Flows

Postman Flows是一种接口测试可视化工具&#xff0c;可以使用流的形式在Postman工作台将请求接口、数据处理和创建实际流程整合到一起。如下图所示 Postman Flows是以API为中心的可视化应用程序开发界面。它提供了一个无限的画布用于编排和串连API&#xff0c;数据可视化来显示…...

系统设计及解决方案

发送验证码 1&#xff1a;根据手机号从Redis中获取value(验证码_时间戳) 2&#xff1a;如果value不为空&#xff0c;并且时间戳与当前时间戳的间隔小于60秒&#xff0c;则返回一个错误信息 3&#xff1a;生成随机验证码 4&#xff1a;调用阿里云短信服务API给用户发送短信验证码…...

从0入门自主空中机器人-2-2【无人机硬件选型-PX4篇】

1. 常用资料以及官方网站 无人机飞控PX4用户使用手册&#xff08;无人机基本设置、地面站使用教程、软硬件搭建等&#xff09;&#xff1a;https://docs.px4.io/main/en/ PX4固件开源地址&#xff1a;https://github.com/PX4/PX4-Autopilot 飞控硬件、数传模块、GPS、分电板等…...

Linux之ARM(MX6U)裸机篇----2.汇编LED驱动实验

一&#xff0c;alpha的LED灯硬件原理分析 STM32 IO初始化流程 ①&#xff0c;使能GPIO时钟 ②&#xff0c;设置IO复用&#xff0c;复用为GPIO ③&#xff0c;配置GPIO的电气属性推挽&#xff0c;上拉下拉 ④&#xff0c;使用GPIO&#xff0c;输出高/低电平 MX6ULL IO初始化…...

e3 1220lv3 cpu-z分数

e3 1220lv3 双核四线程&#xff0c;1.1G频率&#xff0c;最低可在800MHZ运行&#xff0c;TDP 13W。 使用PE启动后测试cpu-z分数。 现在e3 1220lv3的价格落到69元。...

HTML5适配手机

要使 HTML5 网站适配手机设备&#xff0c;您可以遵循以下几个步骤和最佳实践&#xff1a; 1. 使用视口&#xff08;Viewport&#xff09; 在 HTML 文档的 <head> 部分添加视口元标签&#xff0c;以确保页面在移动设备上正确缩放和显示&#xff1a; <meta name"…...

C# 中使用 MassTransit

在生产环境中使用 MassTransit 时&#xff0c;通常需要进行详细的配置&#xff0c;包括设置连接字符串、配置队列、配置消费者、处理重试和错误队列等。以下是一个完整的示例&#xff0c;展示了如何在 ASP.NET Core 应用程序中配置 MassTransit&#xff0c;包括请求/响应模式和…...

网络编程 实现联网 b+Tree

网络编程是客户端和服务器之间通信的基础&#xff0c;也是现代应用开发中不可或缺的技能。在 Unity 中实现网络功能&#xff0c;需要结合计算机网络原理、数据结构与算法&#xff0c;以及网络协议的实际应用。以下是对这一块内容的详细介绍&#xff0c;包括每个涉及到的知识点&…...

zentao ubuntu上安装

#下载ZenTaoPMS-21.2-zbox_amd64.tar.gz&#xff08;https://www.zentao.net/downloads.html&#xff09; 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 在学习完简单的网络编程后&#xff0c;我们将更加深入网络的学习——HTTP协议、TCP协议、UDP协议、IP协议........... IO多路复用 ✨在上一节基于 TCP 协议 编写应用层代码时&#xff0c;我们通过一个线程处理连接的申请&#xff0c;随后通过多线程或者线程…...

Bash Shell知识合集

1. chmod命令 创建一个bash shell脚本 hello.sh ~script $ touch hello.sh脚本创建完成后并不能直接执行&#xff0c;我们要用chmod命令授予它可执行的权限&#xff1a; ~script $ chmod 755 hello.sh授权后的脚本可以直接执行&#xff1a; ~script $ ./hello.sh2.指定运行…...

从0入门自主空中机器人-1【课程介绍】

关于本课程&#xff1a; 本次课程是一套面向对自主空中机器人感兴趣的学生、爱好者、相关从业人员的免费课程&#xff0c;包含了从硬件组装、机载电脑环境设置、代码部署、实机实验等全套详细流程&#xff0c;带你从0开始&#xff0c;组装属于自己的自主无人机&#xff0c;并让…...

Doris使用注意点

自己学习过程中整理&#xff0c;非官方 dws等最后用于查询的表可以考虑使用row存储加快查询&#xff0c;即用空间换时间duplicate key的选择要考虑最常查询使用适当使用bloomfilter 加速查询适当使用aggregate 模式降低max&#xff0c;avg&#xff0c;min之类的计算并加快查询…...

Mybatis插件better-mybatis-generator的下载与使用

1.下载 找到设置 插件 搜索better-mybatis-generator 下载并且重启IDEA 2.连接数据库 点击测试连接 连接成功如下图 3.使用插件 选择对应的表 右击选择 注意&#xff1a;mysql8.0驱动一定要勾上mysql_8 其他地方不要动 然后实体类 mapper xml就都生成好了 mapper里有默认增删…...

HarmonyOS5.0——CodeGenie:鸿蒙生态的AI编程革命​

​​CodeGenie&#xff1a;鸿蒙生态的AI编程革命​​ 华为推出的 ​​CodeGenie​​ 是集成于 DevEco Studio 的 AI 辅助编程工具&#xff0c;专为 HarmonyOS 应用开发设计。它通过深度优化 ArkTS 和 C 语言的代码生成能力&#xff0c;显著提升开发效率&#xff0c;降低鸿蒙生…...

技巧小结:根据寄存器手册写常用外设的驱动程序

需求&#xff1a;根据STM32F103寄存器手册写DMA模块的驱动程序 一、分析标准库函数的写法&#xff1a; 各个外设的寄存器地址定义在stm32f10x.h文件中&#xff1a;此文件由芯片厂家提供;内核的有关定义则定义在core_cm3.h文件中&#xff1a;ARM提供; 1、查看外设区域多级划分…...

cv::FileStorage用法

cv::FileStorage 是 OpenCV 中的一个类&#xff0c;用于读取和写入结构化数据&#xff08;如 YAML、XML、JSON&#xff09;。它非常适合保存和加载诸如&#xff1a; 相机内参&#xff08;K、D&#xff09; 位姿&#xff08;R、T&#xff09; 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)

摘要&#xff1a;文章深入剖析美业现状与挑战&#xff0c;指出其市场规模庞大但竞争激烈&#xff0c;面临获客难、成本高、服务标准化缺失等问题。随后阐述 AI 智能体与数据驱动决策的概念&#xff0c;强调其在美业管理中的重要性。接着详细说明 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 # 关闭保护模式&#xff08;生产环境建议结合密码使用&#xff09; port 6379 # 默认端口 daemonize no …...

测试(面经 八股)

目录 前言 一&#xff0c;软件测试&#xff08;定义&#xff09; 1&#xff0c;定义 2&#xff0c;目的 3&#xff0c;价值 4&#xff0c;实践 二&#xff0c;软件测试&#xff08;目的&#xff09; 1&#xff0c;找 bug 2&#xff0c;验证达标 3&#xff0c;质量评价…...

【深度学习新浪潮】如何入门三维重建?

入门三维重建算法技术需要结合数学基础、计算机视觉理论、编程实践和项目经验,以下是系统的学习路径和建议: 一、基础知识储备 1. 数学基础 线性代数:矩阵运算、向量空间、特征分解(用于相机矩阵、变换矩阵推导)。几何基础:三维几何(点、线、面的表示)、射影几何(单…...

Jetpack Compose 中,DisposableEffect、LaunchedEffect 和 sideEffect 区别和用途

在 Jetpack Compose 中&#xff0c;DisposableEffect、LaunchedEffect 和 sideEffect 都是用于处理副作用&#xff08;Side Effects&#xff09;的 API&#xff0c;但它们的用途和触发时机不同。以下是它们的核心概念和区别&#xff1a; 1. 副作用&#xff08;Side Effect&…...