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

MTK-系统设置Settings 开机累计时长源码分析

梳理开机累计时长的源码,分析实现方式

文章目录

  • 前言
  • 一、需求
    • 实现方案
  • 二、实现思路
  • 三、源码分析
    • 相关源码文件
    • 参考资料
    • 设置的页面-MyDeviceInfoFragment
    • 设置的页面-开机累计时长控制器-UptimePreferenceController和关联的AbstractUptimePreferenceController
      • 小结
    • 设置的页面-开机累计时长关联的布局 my_device_info
  • 四、理解 SystemClock.elapsedRealtime
    • 基本概念
    • 与相关方法的比较
    • 主要特点
      • 不受系统时间更改影响:
      • 包含深度睡眠时间:
      • 单调递增:
  • 五、总结


前言

我记得以前有客户要做限制开机使用时长功能,机器开机一段时间后自动关机功能。 当时想法就是通过开机累计时长功能实现。


一、需求

实现机器开机后,指定小时后 自动关机功能。

实现方案

  • 开机统计时长本身就有现成的api, 在自己的系统签名应用里面统计时长,到大时长后自动触发关机业务逻辑
  • 很多产品本身是没有定制的应用的,或者集成了部分第三方应用而已。 此时 统计开机时长的逻辑就需要系统 framework 层实现了。

二、实现思路

参考系统设置 开机累计时长 实现方式实现:
虽然已经有了实现方案了,但是还是强烈建议 看看系统设置源码是怎么实现的,系统源码还是值得分析、梳理业务的。

在这里插入图片描述

三、源码分析

相关源码文件

/packages/apps/Settings/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
/packages/apps/Settings/src/com/android/settings/deviceinfo/UptimePreferenceController.java
/packages/apps/Settings/res/xml/my_device_info.xml
/frameworks/base/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java

参考资料

RKAndroid11-系统设置新增开关选项
这里建议看看,如果对系统源码Settings 本身就已经有一定的了解,就不用参考了。 主要理解 Controller、布局、布局属性的关联关系。

设置的页面-MyDeviceInfoFragment

找到统计时长对应的页面,如下:
在这里插入图片描述
还是看看日志 这个页面对应的fragment 是哪一个,日志如下:
在这里插入图片描述
找到 Fragment 页面的目的是找对应的 布局xml 文件和 控制Controler 如下:
在这里插入图片描述

  @Overrideprotected int getPreferenceScreenResId() {return R.xml.my_device_info;}

设置的页面-开机累计时长控制器-UptimePreferenceController和关联的AbstractUptimePreferenceController

UptimePreferenceController 源码如下,发现非常简单,那么它的逻辑应该就在父类AbstractUptimePreferenceController里面了,代码如下

/*** Concrete subclass of uptime preference controller*/
public class UptimePreferenceController extends AbstractUptimePreferenceControllerimplements PreferenceControllerMixin {public UptimePreferenceController(Context context, Lifecycle lifecycle) {super(context, lifecycle);}// This space intentionally left blank
}

/*** Preference controller for uptime*/
public abstract class AbstractUptimePreferenceController extends AbstractPreferenceControllerimplements LifecycleObserver, OnStart, OnStop {@VisibleForTestingstatic final String KEY_UPTIME = "up_time";private static final int EVENT_UPDATE_STATS = 500;private Preference mUptime;private Handler mHandler;public AbstractUptimePreferenceController(Context context, Lifecycle lifecycle) {super(context);if (lifecycle != null) {lifecycle.addObserver(this);}}@Overridepublic void onStart() {getHandler().sendEmptyMessage(EVENT_UPDATE_STATS);}@Overridepublic void onStop() {getHandler().removeMessages(EVENT_UPDATE_STATS);}@Overridepublic boolean isAvailable() {return true;}@Overridepublic String getPreferenceKey() {return KEY_UPTIME;}@Overridepublic void displayPreference(PreferenceScreen screen) {super.displayPreference(screen);mUptime = screen.findPreference(KEY_UPTIME);updateTimes();}private Handler getHandler() {if (mHandler == null) {mHandler = new MyHandler(this);}return mHandler;}private void updateTimes() {mUptime.setSummary(DateUtils.formatElapsedTime(SystemClock.elapsedRealtime() / 1000));}private static class MyHandler extends Handler {private WeakReference<AbstractUptimePreferenceController> mStatus;public MyHandler(AbstractUptimePreferenceController activity) {mStatus = new WeakReference<>(activity);}@Overridepublic void handleMessage(Message msg) {AbstractUptimePreferenceController status = mStatus.get();if (status == null) {return;}switch (msg.what) {case EVENT_UPDATE_STATS:status.updateTimes();sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000);break;default:throw new IllegalStateException("Unknown message " + msg.what);}}}
}

可以看到,AbstractUptimePreferenceController 源码里面处理了开机累计时长的业务和实现。 通过 handler 发送 EVENT_UPDATE_STATS 事件,每秒更新一次。

status.updateTimes(); --private void updateTimes() {mUptime.setSummary(DateUtils.formatElapsedTime(SystemClock.elapsedRealtime() / 1000));
}                    ---》mUptime.setSummary --》mUptime = screen.findPreference(KEY_UPTIME); KEY_UPTIME 是什么,不就是key 嘛,它就是布局里面唯一性的key,拿到展示数据的 Preference

小结

这里的开机累计时长逻辑很清晰

  • handler 使用
  • 获取 开机累计时长的 Preference, 并调用 setSummary 每秒更新数据
  • 统计累计时长用到一个api SystemClock.elapsedRealtime()

设置的页面-开机累计时长关联的布局 my_device_info

        。。。。。。。。<!-- Device up time --><Preferenceandroid:key="up_time"android:order="48"android:title="@string/status_up_time"android:summary="@string/summary_placeholder"android:selectable="false"/>。。。。。。。。

这里需要强调的是 这个 key 不就代表唯一性嘛,在上面的Controler里面通过 screen.findPreference(KEY_UPTIME); 找到 开机累计时长的item,然后设置setSummary 数据。

四、理解 SystemClock.elapsedRealtime

SystemClock.elapsedRealtime() 是 Android 系统提供的一个非常重要的计时方法,用于获取设备从启动到现在经过的时间(包括深度睡眠时间)。

基本概念

  • 返回值:返回自系统启动以来的毫秒数,包括设备处于深度睡眠的时间

  • 时钟类型:这是一个"单调时钟"(monotonic clock),意味着它只会向前走,不会受系统时间设置的影响

  • 基准点:从设备上次启动开始计时,设备重启后会重置

与相关方法的比较

方法描述受系统时间设置影响包含睡眠时间
SystemClock.elapsedRealtime()自启动以来的时间(包括睡眠)
SystemClock.uptimeMillis()自启动以来的时间(不包括睡眠)
System.currentTimeMillis()当前系统时间(墙钟时间)不适用

主要特点

不受系统时间更改影响:

  • 即使用户手动修改了设备时间,这个值也不会受到影响

  • 适合用于需要精确计算时间间隔的场景

包含深度睡眠时间:

  • 即使设备进入深度睡眠状态,这个时钟也会继续计时

  • 适合记录设备的总运行时间

单调递增:

  • 保证每次调用返回的值都大于或等于前一次调用的值

  • 不会出现时间回退的情况

五、总结

  • 这里针对一个简单需求,去分析了系统设置Settings 开机累计时长 关联的源码进行了分析
  • 这里其实就是一个api 的应用 SystemClock.elapsedRealtime。 如果需求是 控制 使用机器时间,那么就是另外关联的一个api 也可以实现了。
http://www.dtcms.com/a/271440.html

相关文章:

  • AI芯片产品经理:算力革命的架构师
  • Mysql底层专题(七)MVCC多版本并发控制机制
  • STM32-定时器输入捕获
  • 高级LoRA:面向垂直领域LLM的实战微调指南——LoRA合并、续训、堆叠,Checkpoint管理
  • 佰力博PEAI压电分析仪-精准测量压电材料d33系数
  • RAG实战指南 Day 11:文本分块策略与最佳实践
  • HCIP(综合实验)
  • 腾讯位置商业授权未来驾车ETA(批量)
  • Fluent许可配置常见问题
  • ARM汇编编程(AArch64架构)课程 - 第8章:控制流与循环
  • 数字化管理新趋势:权限分级看板如何筑牢安全防线
  • 【Java】【力扣】【字节高频】3.无重复字符的最长字串
  • HTTP API 身份认证
  • 【Qt】Qt QML json处理
  • 微信获取access_token授权的两种不同情况
  • 零成本实现文本转语音
  • python网络爬虫笔记21:天地图解析服务调用教程
  • 正点原子学习 用户权限管理
  • 海康威视监控相机实时性研究
  • 深度学习遇到的问题
  • 一[3.7] YOLO系列基础(2)- “Bottleneck模块详解”
  • JavaScript对象的深度拷贝
  • 17.Spring Boot的Bean详解(新手版)
  • 十、Rocky Linux 9.x 在线安装Nginx 1.28.0
  • 豆包编写Java程序小试
  • 电子元器件基础知识总结
  • 基于SpringBoot+Vue的疫情问卷调查与返校信息管理系统】前后端分离
  • 城市地质大数据平台:透视地下空间,赋能智慧未来
  • git断点续传,中断后继续下载
  • 【计算机三级网络】——IP校园网大题(第二道):路由代码填空