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

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


前言

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


一、需求

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

实现方案

  • 开机统计时长本身就有现成的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 如下:
在这里插入图片描述

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

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

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

/**
 * Concrete subclass of uptime preference controller
 */
public class UptimePreferenceController extends AbstractUptimePreferenceController
        implements PreferenceControllerMixin {
    public UptimePreferenceController(Context context, Lifecycle lifecycle) {
        super(context, lifecycle);
    }

    // This space intentionally left blank
}

/**
 * Preference controller for uptime
 */
public abstract class AbstractUptimePreferenceController extends AbstractPreferenceController
        implements LifecycleObserver, OnStart, OnStop {

    @VisibleForTesting
    static 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);
        }
    }

    @Override
    public void onStart() {
        getHandler().sendEmptyMessage(EVENT_UPDATE_STATS);
    }

    @Override
    public void onStop() {
        getHandler().removeMessages(EVENT_UPDATE_STATS);
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_UPTIME;
    }

    @Override
    public 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);
        }

        @Override
        public 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 -->
        <Preference
            android: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 也可以实现了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值