提案:无需后台常驻的醒目全屏语音提醒
1. 功能描述
本模块在 App 创建提醒后,将未来触发时间登记到 Android 系统 AlarmManager。到点时,即使 App 不在前台或进程已被普通回收,系统仍可重新启动 App 的广播接收器;App 随后启动前台服务,在当前桌面或其他普通 App 上方显示可操作的全屏提醒,并使用闹钟音频通道播放语音。
用户可以在 App 中静默取消尚未触发的提醒,触发后通过全屏界面的“停止闹钟”结束提醒。当前测试实现使用 Edge TTS 生成的内置 MP3;提醒方式可在后续扩展为语音、震动、语音加震动或仅界面。
核心能力包括:
| 维度 |
能力 |
示例 |
| 系统级调度 |
使用 AlarmManager.setAlarmClock() 登记未来任务 |
创建明天 09:00 的提醒后,系统负责到点唤醒广播接收器 |
| 进程独立触发 |
Receiver 由清单声明,App 普通进程不存在时可被系统重新创建 |
用户划走 App 或系统普通回收进程后,仍能触发 |
| 跨 App 可见 |
前台服务添加 TYPE_APPLICATION_OVERLAY 全屏窗口 |
用户正在聊天、浏览网页或停留在桌面时,仍看到停止界面 |
| 锁屏后备 |
高优先级闹钟通知关联 fullScreenIntent 和锁屏 Activity |
息屏/锁屏时显示 RingActivity 后备页面 |
| 语音提醒 |
App 自己的 MediaPlayer 播放内置 Edge TTS MP3,并循环播放 |
播报“您设置的时间到了,请点击停止闹钟” |
| 停止处理 |
App 内取消未来任务,或在全屏界面点击停止 |
取消任务后不跳转系统时钟页面 |
这里的“系统闹钟”指 Android AlarmManager 的系统级闹钟任务。系统可以将下一个闹钟显示在状态栏或锁屏,但不承诺一定把它写入小米等厂商“时钟”App 的闹钟列表;本模块的核心目标是系统可靠触发和用户可见处理界面。
2. 用户故事
目标用户:希望提醒足够醒目,并且不希望为了收到提醒而让 App 一直保持后台常驻的用户。
用户在 App 中创建一个未来提醒后,希望可以正常退出或关闭 App,无需手动维持后台运行。到点时,即使用户正在其他 App、停留在桌面、处于锁屏状态,或 App 进程已被系统普通回收,手机仍应出现醒目的全屏提醒并播报语音,让用户立即知道提醒来自哪里以及应该如何处理。
用户点击“停止闹钟”后,希望语音、悬浮窗、通知和前台服务全部结束,不需要进入系统时钟页面手动处理。
用户在 App 内取消一个尚未触发的提醒,希望手机端立即静默取消对应的系统任务,不需要跳转到系统时钟页面。
用户手机暂时离线时,希望已经登记的本地提醒仍能触发,不依赖网络连接。
3. 现有做法及不足
常见的简单实现通常存在以下问题:
- 只在 Activity 中使用
Handler 或计时器,App 退出后任务消失。
- 只发送普通通知,用户在其他 App 中可能只看到通知或听到声音,不知道如何停止。
- 只使用
fullScreenIntent,但在解锁状态下 Android/HyperOS 可能只显示抬头通知,不保证 Activity 抢占前台。
- 触发时临时调用在线 TTS,断网或厂商限制 TTS 进程时可能无声。
- 删除一个未来任务时无条件停止全局响铃服务,可能影响另一个正在响铃的提醒。
本提案采用 AlarmManager → BroadcastReceiver → Foreground Service → Overlay/Notification/MediaPlayer 链路解决上述问题。时间选择器只是产生 triggerAtMillis 的一种 UI,不是本能力的核心。
4. 本期范围
- 接收一个未来的绝对时间戳
triggerAtMillis,登记 Android AlarmManager.setAlarmClock() 任务。
- 持久化触发时间和取消/重建系统任务所需的稳定字段。
- 使用清单声明的显式
BroadcastReceiver,保证 App 普通进程死亡后仍可由系统重新启动。
- 广播到点后启动媒体播放类型的前台服务,并立即调用
startForeground()。
- 服务发布高重要级别、
CATEGORY_ALARM 的持续通知。
- 获得悬浮窗授权后,服务使用
TYPE_APPLICATION_OVERLAY 展示包含当前时间、提醒来源和“停止闹钟”按钮的全屏界面。
- 锁屏或系统允许时,通过通知
fullScreenIntent 提供 RingActivity 后备页面。
- 使用 APK 内置 Edge TTS MP3,通过
USAGE_ALARM + CONTENT_TYPE_SPEECH 播放并循环。
- App 内取消尚未触发的提醒时,静默取消对应的系统任务。
- 停止当前响铃时,移除悬浮窗、停止播放器、取消通知、停止服务并关闭响铃 Activity。
- 引导用户授权精确闹钟、通知、全屏通知、悬浮窗和电池优化相关权限。
5. 明确不做
- 不依赖 Activity 常驻、
Handler 计时器或 App 一直处于前台。
- 不承诺用户强行停止 App 后仍能绕过 Android stopped 状态触发。
- 不承诺支付页、密码页、授权页等设置了
HIDE_NON_SYSTEM_OVERLAY_WINDOWS 的敏感页面一定能显示第三方悬浮窗。
- 不承诺解锁状态下全屏通知一定抢占当前 Activity;解锁场景主要依赖悬浮窗。
- 不在响铃触发时依赖网络在线合成 TTS;当前语音资源在构建阶段生成并随 APK 打包。
- 不承诺卸载后保留系统任务。
- 当前版本不承诺手机重启后自动恢复任务;若产品需要,另行增加
BOOT_COMPLETED 重建方案。
- 当前版本不实现多个提醒同一时刻触发时的完整队列体验;生产版需要增加活动响铃队列。
- 不把本模块描述为已经写入小米“时钟”App 的用户闹钟列表;实际使用的是 Android 系统
AlarmManager。
- 不在本期扩展地点、天气、蓝牙、设备状态等智能情境提醒。
6. 关键决策
| 决策点 |
备选方案 |
选择 |
理由 |
| 系统调度 |
Activity 计时器 / 普通通知定时 / AlarmManager |
setAlarmClock() |
任务由系统保存,适合用户可感知的精确闹钟 |
| 到点入口 |
动态 Receiver / 清单 Receiver |
清单显式 Receiver |
App 进程不存在时,系统仍能重新创建组件 |
| 后台执行 |
普通 Service / Foreground Service |
媒体播放 Foreground Service |
Android 8+ 后台启动和持续播放需要前台服务资格 |
| 解锁时可见 |
只用 full-screen Activity / Overlay |
Overlay + full-screen 通知后备 |
解锁时系统可能不允许通知 Activity 抢前台,Overlay 更稳定 |
| 锁屏处理 |
只用 Overlay / 只用 Activity |
两者结合 |
Overlay 负责普通界面,锁屏 Activity 负责系统后备路径 |
| 取消方式 |
跳转系统时钟 / App 本地静默取消 |
App 本地静默取消 |
用户不需要离开当前 App,系统任务由 App 自己结束 |
| 语音来源 |
触发时在线 TTS / 系统 TTS / 内置 MP3 |
内置 MP3 + MediaPlayer |
不依赖网络和独立 TTS 进程,音频行为可控 |
| 重启恢复 |
不恢复 / 开机 Receiver 重建 |
本期不做,后续可选 |
Android 默认不保证 AlarmManager 任务跨重启保留 |
7. 边界与异常
| 情况 |
处理方式 |
| 精确闹钟权限未开启 |
不调用 setAlarmClock();引导用户进入 ACTION_REQUEST_SCHEDULE_EXACT_ALARM |
| 悬浮窗权限未开启 |
仍可保留通知/后备路径,但不能承诺解锁时全屏覆盖;引导 ACTION_MANAGE_OVERLAY_PERMISSION |
| 通知权限或全屏通知权限未开启 |
保留可用路径并明确提示;通知权限缺失会影响前台服务可见性和通知入口 |
| 电池优化或 HyperOS 后台限制 |
引导用户设置“无限制”、允许后台弹出/自启动;不能用 App 代码绕过厂商策略 |
| 选择的时间已过去 |
拒绝创建并要求重新提供未来时间戳 |
| 系统任务取消信息缺失 |
记录取消失败原因,不删除本地记录,避免 UI 与系统状态不一致 |
| 用户取消未来任务 |
只取消对应的系统任务,不停止其他正在响铃的服务 |
| 当前提醒正在响铃 |
停止播放器、Overlay、通知和响铃 Activity,并清除当前任务记录 |
| App 被强行停止 |
不承诺到点触发,等待用户重新启动 App 后恢复可用 |
| 手机重启 |
当前版本不自动恢复;生产版增加 RECEIVE_BOOT_COMPLETED 和未来任务重建 |
| 敏感系统页面隐藏 Overlay |
接受 Android 安全行为,保留通知/音频可用性,不声称能覆盖该页面 |
| MP3 播放失败 |
记录错误并保留全屏 UI/通知,生产版可增加本地备用音频 |
| 用户关闭闹钟通知渠道声音 |
当前 App 语音由 MediaPlayer 播放,通知渠道不作为唯一声音来源;仍需尊重系统勿扰和音量设置 |
| 同一时间多个提醒触发 |
当前测试版只保证基础提醒能力;生产版增加活动响铃队列或合并提醒界面 |
8. 基本概念与信息结构
8.1 LocalReminderRecord(设备本地)
LocalReminderRecord
├─ triggerAtMillis: long(未来绝对时间)
├─ systemTaskBinding: 重建和取消系统任务所需的内部字段
├─ reminderMode: VOICE | VIBRATION | VOICE_AND_VIBRATION(可扩展字段)
├─ status: scheduled | firing | cancelled | completed
└─ createdAt / updatedAt
系统任务绑定字段只用于 App 自己重建和取消 PendingIntent,不作为用户界面或业务层概念。
当前测试 APK 已实现 VOICE;VIBRATION 和 VOICE_AND_VIBRATION 可以复用同一服务,在触发时选择是否创建 MediaPlayer 和 Vibrator。
8.2 触发链路
业务模块提供 triggerAtMillis
→ 构造系统广播 PendingIntent 并持久化取消所需字段
→ AlarmManager.setAlarmClock()
→ Android 到点发送显式广播
→ AlarmReceiver.startForegroundService()
→ AlarmSoundService.startForeground()
→ Notification + TYPE_APPLICATION_OVERLAY + MediaPlayer
→ 用户点击“停止闹钟”
→ cancel overlay / player / notification / service
8.3 提醒方式扩展
提醒方式不应影响系统调度任务本身:
VOICE
→ MediaPlayer + USAGE_ALARM
VIBRATION
→ Vibrator/VibratorManager + VIBRATE 权限
VOICE_AND_VIBRATION
→ 同时启用 MediaPlayer 与 Vibrator
SCREEN_ONLY
→ 只显示 Overlay/Activity,不播放声音或震动
通知渠道的声音和震动配置创建后受系统管理,因此“仅震动”最好由服务直接控制 Vibrator,而不是依赖动态修改同一个通知渠道。
9. 验收标准
- 业务模块提供一个未来
triggerAtMillis 后,设备成功登记 Android AlarmManager 闹钟;不要求时间必须来自某一种选择器。
- 用户切换到其他 App、回到桌面或 App 进程被普通回收后,任务仍能到点触发。
- 到点后确认前台服务正在运行、通知存在、普通其他 App 上方出现全屏 Overlay,且界面明确显示提醒来源和停止按钮。
- 播放 Edge TTS 语音时使用
USAGE_ALARM;断网情况下仍能播放 APK 内置 MP3。
- 在 App 内取消尚未触发的提醒后,系统任务被静默取消,不跳转系统时钟页面。
- 点击停止后,Overlay 消失、MediaPlayer 停止、通知消失、服务结束,且不会留下循环回调。
- 锁屏/息屏时测试
fullScreenIntent 的 RingActivity 后备路径;接受系统对全屏通知的最终调度权。
- 在支付、授权或密码等敏感页面测试时,接受第三方 Overlay 被系统隐藏的限制。
- 小米 14 / HyperOS 真机检查悬浮窗、通知、全屏通知、电池优化和后台弹出权限。
- 文档明确:强行停止、卸载、重启恢复和多个同时触发队列是否属于当前版本能力。
ADB 验收证据
查看系统闹钟:
adb shell dumpsys alarm | rg "包名|FIRE_ALARM"
确认系统已保存应用闹钟任务:
adb shell dumpsys activity intents | rg "包名|broadcastIntent"
确认悬浮窗:
adb shell dumpsys window windows | rg "APPLICATION_OVERLAY|包名"
确认前台服务:
adb shell dumpsys activity services 包名 | rg "AlarmSoundService|isForeground"
确认闹钟语音播放器:
adb shell dumpsys audio | rg "包名|USAGE_ALARM|CONTENT_TYPE_SPEECH"
测试普通进程死亡可使用 adb shell am kill 包名;不要把 adb shell am force-stop 包名 当成普通进程死亡场景。
提案:无需后台常驻的醒目全屏语音提醒
1. 功能描述
本模块在 App 创建提醒后,将未来触发时间登记到 Android 系统
AlarmManager。到点时,即使 App 不在前台或进程已被普通回收,系统仍可重新启动 App 的广播接收器;App 随后启动前台服务,在当前桌面或其他普通 App 上方显示可操作的全屏提醒,并使用闹钟音频通道播放语音。用户可以在 App 中静默取消尚未触发的提醒,触发后通过全屏界面的“停止闹钟”结束提醒。当前测试实现使用 Edge TTS 生成的内置 MP3;提醒方式可在后续扩展为语音、震动、语音加震动或仅界面。
核心能力包括:
AlarmManager.setAlarmClock()登记未来任务TYPE_APPLICATION_OVERLAY全屏窗口fullScreenIntent和锁屏 ActivityRingActivity后备页面MediaPlayer播放内置 Edge TTS MP3,并循环播放这里的“系统闹钟”指 Android
AlarmManager的系统级闹钟任务。系统可以将下一个闹钟显示在状态栏或锁屏,但不承诺一定把它写入小米等厂商“时钟”App 的闹钟列表;本模块的核心目标是系统可靠触发和用户可见处理界面。2. 用户故事
目标用户:希望提醒足够醒目,并且不希望为了收到提醒而让 App 一直保持后台常驻的用户。
用户在 App 中创建一个未来提醒后,希望可以正常退出或关闭 App,无需手动维持后台运行。到点时,即使用户正在其他 App、停留在桌面、处于锁屏状态,或 App 进程已被系统普通回收,手机仍应出现醒目的全屏提醒并播报语音,让用户立即知道提醒来自哪里以及应该如何处理。
用户点击“停止闹钟”后,希望语音、悬浮窗、通知和前台服务全部结束,不需要进入系统时钟页面手动处理。
用户在 App 内取消一个尚未触发的提醒,希望手机端立即静默取消对应的系统任务,不需要跳转到系统时钟页面。
用户手机暂时离线时,希望已经登记的本地提醒仍能触发,不依赖网络连接。
3. 现有做法及不足
常见的简单实现通常存在以下问题:
Handler或计时器,App 退出后任务消失。fullScreenIntent,但在解锁状态下 Android/HyperOS 可能只显示抬头通知,不保证 Activity 抢占前台。本提案采用
AlarmManager → BroadcastReceiver → Foreground Service → Overlay/Notification/MediaPlayer链路解决上述问题。时间选择器只是产生triggerAtMillis的一种 UI,不是本能力的核心。4. 本期范围
triggerAtMillis,登记 AndroidAlarmManager.setAlarmClock()任务。BroadcastReceiver,保证 App 普通进程死亡后仍可由系统重新启动。startForeground()。CATEGORY_ALARM的持续通知。TYPE_APPLICATION_OVERLAY展示包含当前时间、提醒来源和“停止闹钟”按钮的全屏界面。fullScreenIntent提供RingActivity后备页面。USAGE_ALARM + CONTENT_TYPE_SPEECH播放并循环。5. 明确不做
Handler计时器或 App 一直处于前台。HIDE_NON_SYSTEM_OVERLAY_WINDOWS的敏感页面一定能显示第三方悬浮窗。BOOT_COMPLETED重建方案。AlarmManager。6. 关键决策
AlarmManagersetAlarmClock()7. 边界与异常
setAlarmClock();引导用户进入ACTION_REQUEST_SCHEDULE_EXACT_ALARMACTION_MANAGE_OVERLAY_PERMISSIONRECEIVE_BOOT_COMPLETED和未来任务重建8. 基本概念与信息结构
8.1 LocalReminderRecord(设备本地)
系统任务绑定字段只用于 App 自己重建和取消
PendingIntent,不作为用户界面或业务层概念。当前测试 APK 已实现
VOICE;VIBRATION和VOICE_AND_VIBRATION可以复用同一服务,在触发时选择是否创建MediaPlayer和Vibrator。8.2 触发链路
8.3 提醒方式扩展
提醒方式不应影响系统调度任务本身:
通知渠道的声音和震动配置创建后受系统管理,因此“仅震动”最好由服务直接控制
Vibrator,而不是依赖动态修改同一个通知渠道。9. 验收标准
triggerAtMillis后,设备成功登记 AndroidAlarmManager闹钟;不要求时间必须来自某一种选择器。USAGE_ALARM;断网情况下仍能播放 APK 内置 MP3。fullScreenIntent的RingActivity后备路径;接受系统对全屏通知的最终调度权。ADB 验收证据
查看系统闹钟:
确认系统已保存应用闹钟任务:
确认悬浮窗:
确认前台服务:
确认闹钟语音播放器:
测试普通进程死亡可使用
adb shell am kill 包名;不要把adb shell am force-stop 包名当成普通进程死亡场景。