文章目录
DeskClock
Android台钟
前言
Deskclock 是 Android 自带的一个核心应用,肩负 Android 时刻相关的基本功能,提供闹钟、时钟、倒计时、秒表服务。相信时钟、闹钟对于大多数用户来说,是经常使用的功能。笔者就是靠手机看时间,闹钟数量也是满满的占了两屏。己见,Deskclock 作为 Android 系统基本服务功能的提供者,责任重大。
本文将从时钟、闹钟、倒计时、秒表、其它分 5 个模块讲述 Deskclock 。本文基于 Android Q 平台源码就行阐述。
整体架构
时钟
时钟提供两个功能:
- 数字时钟
- 查看添加不同时区时间(世界时间)
如上图所示。
类图
总体功能就是一个主时钟和世界时钟,时钟的展示方式可以是数字时钟(TextClock)或者模拟现实时钟(AnalogClock)。世界时钟交由 RecyclerView 绘制,用户可以添加世界各地的时钟。
闹钟
Alarm
闹钟的参考图,分两部分,上面部分是一个模拟现实时钟,下面部分是用户设置的闹钟列表。
类图
如上类图,总结如下内容:
-
UI 部分的绘制由 AlarmClockFragment 来完成,其中模拟数字时钟交由 DialPlate 来完成,闹钟列表交由 AlarmRecyclerView 完成,用户点击逻辑交由 AlarmTimeClickHandler 来处理。
-
组件中闹钟数据传递主要通过 Alarm.java 来封装数据。
-
闹钟的添加和编辑交由 AlarmSettingsActivity 来完成。
-
通过 Loader 机制来加载闹钟数据。
-
闹钟数据交由 ClockProvider 实现固化和查询。
-
闹钟相应 UI 和闹钟铃声交由 AlarmActivity、AlarmNotifications、AlarmKlaxon 完成。
创建编辑闹钟
创建闹钟的流程如上序列图,编辑闹钟则也是从 AlarmSettingsActivity 开始,该图不包含创建、编辑闹钟的参数编辑流程(如时间、重复、铃声、标签等等)
删除闹钟
删除闹钟如上序列图,需要清除闹钟的通知、状态、铃声(如果在响)等,删除固化到数据库的 alarm_instances 和 alarm_templates,还通过 Snackbar 限时撤销,如果误删可以通过撤销来恢复闹钟,恢复闹钟的流程,基本就是重新创建该闹钟的过程。更多细节就不再赘述了,关键的节点在如上的序列图也添加了说明。
闹钟响了
闹钟触发,在上文中“创建编辑闹钟”章节中可以知道,闹钟的触发,有 AlarmManager 调起 DeskClock 的 AlarmService。
Alarm instances database table
Alarm database table
AlarmManager数据
设置闹钟后,在 AlarmManager 侧的数据如下
Batch{14894e1 num=1 start=1720413714 end=1720413714 flgs=0x9}:
RTC_WAKEUP #0: Alarm{55330ce type 0 when 1578524400000 flags 9 windowLength 0 com.android.deskclock 1000}
tag=*walarm*:com.android.deskclock.change_state
type=0 expectedWhenElapsed=+14h22m53s647ms expectedMaxWhenElapsed=+14h22m53s647ms whenElapsed=+14h22m53s647ms maxWhenElapsed=+14h22m53s647ms when=2020-01-09 07:00:00.000
window=0 repeatInterval=0 count=0 flags=0x9
operation=PendingIntent{a9ebbef: PendingIntentRecord{cb306fc com.android.deskclock startService}}
Batch{e87a6f4 num=1 start=1727613714 end=1727613714 flgs=0x3}:
RTC_WAKEUP #0: Alarm{9589e1d type 0 when 1578531600000 flags 3 windowLength 0 com.android.deskclock 1000}
tag=*walarm*:indicator
type=0 expectedWhenElapsed=+16h22m53s647ms expectedMaxWhenElapsed=+16h22m53s647ms whenElapsed=+16h22m53s647ms maxWhenElapsed=+16h22m53s647ms when=2020-01-09 09:00:00.000
window=0 repeatInterval=0 count=0 flags=0x3
Alarm clock:
triggerTime=2020-01-09 09:00:00.000
showIntent=PendingIntent{2565892: PendingIntentRecord{c2fc486 com.android.deskclock startActivity}}
operation=PendingIntent{ac6263: PendingIntentRecord{ff92a0f com.android.deskclock broadcastIntent}}
Next wake from idle: Alarm{9589e1d type 0 when 1578531600000 flags 3 windowLength 0 com.android.deskclock 1000}
tag=*walarm*:indicator
type=0 expectedWhenElapsed=+16h22m53s647ms expectedMaxWhenElapsed=+16h22m53s647ms whenElapsed=+16h22m53s647ms maxWhenElapsed=+16h22m53s647ms when=2020-01-09 09:00:00.000
window=0 repeatInterval=0 count=0 flags=0x3
Alarm clock:
triggerTime=2020-01-09 09:00:00.000
showIntent=PendingIntent{2565892: PendingIntentRecord{c2fc486 com.android.deskclock startActivity}}
operation=PendingIntent{ac6263: PendingIntentRecord{ff92a0f com.android.deskclock broadcastIntent}}
秒表
秒表界面如上图所示,上半部分为一个自定义的计时器,中间部分为秒表打点计次数据,底部则是三个按钮,中间按钮可以暂定,左侧按钮重置秒表,右侧按钮可以打点计次,当秒表暂定时,右侧按钮是分享按钮。
类图
秒表界面相对闹钟要简少一些,自定义计时器主要由 StopwatchCircleView、AutoSizingTextView 来完成,中间部分有 RecyclerView 和 LapsAdapter 来完成。逻辑成员主要有 Stopwatch、StopwatchService、StopwatchModel、StopwatchDAO 等。
开始计时
按下开始按钮,开始秒表计时
如上流程包括秒表计时的流程,重置、打点计次的流程
计时器
计时器和秒表基本相似,就不展开阐述了。
其它
对外接口
DeskClock 的对外接口由 HandleApiCalls 来处里,接收如下 action:
<action android:name="android.intent.action.DISMISS_ALARM" />
<action android:name="android.intent.action.SHOW_ALARMS" />
<action android:name="android.intent.action.SHOW_TIMERS" />
<action android:name="android.intent.action.SNOOZE_ALARM" />
#require permission com.android.alarm.permission.SET_ALARM
<action android:name="android.intent.action.SET_ALARM" />
<action android:name="android.intent.action.SET_TIMER" />
对于对外接口处理,本文不再展开阐述。
Widget
Widget 交由 DigitalAppWidgetProvider 来完成,本文不再展开阐述。
设置
Deskclock 设置交由 SettingsActivity 完成。可以对闹钟音量等进行个性话设置,本文就不再展开阐述。