Android8.1 MTK平台 增加定时开关机功能

前言

定时开机需要底层 RTC 时钟支持,本文只针对 MTK 平台,其它平台不一定能适用请慎重参考文末链接

定时开关机的原理其实和闹钟是一样的,只不过是个特殊的闹钟而已,由于之前 MTK 6.0 的系统中自带就有定时开关机的功能(在设置中嵌入菜单),

8.1 中我们也将在设置界面中嵌入此功能。

代码

直接 copy 6.0 中的 SchedulePowerOnOff 源码,如果你没有可下载我提供的,将 app 源码放置到 *vendor\mediatek\proprietary\packages\apps* 路径下

修改一 在 AndroidManifest.xml 中增加 Settings 配置(下载的源码中已经修改过)

	<activity android:name="com.mediatek.schpwronoff.AlarmClock"
            android:label="@string/schedule_power_on_off_settings_title"
            android:configChanges="orientation|keyboardHidden|keyboard|navigation">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <action android:name="com.android.settings.SCHEDULE_POWER_ON_OFF_SETTING" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <!--add for settings show quick into -->
        <intent-filter android:priority="5">
            <action android:name="com.android.settings.action.EXTRA_SETTINGS" />
        </intent-filter>
        <meta-data
            android:name="com.android.settings.category"
            android:value="com.android.settings.category.ia.homepage" />
        <meta-data
            android:name="com.android.settings.icon"
            android:resource="@drawable/ic_settings_schpwronoff" />
            <!-- end -->
    </activity>

修改二 在 MtkAlarmManagerService 中添加 SchedulePowerOnOff 的包名

vendor\mediatek\proprietary\frameworks\base\services\core\java\com\mediatek\server\MtkAlarmManagerService.java

/**
 *For PowerOffalarm feature, this function is used for AlarmManagerService
 * to set the latest alarm registered
 */
private void resetPoweroffAlarm(Alarm alarm) {

        String setPackageName = alarm.operation.getTargetPackage();
        long latestTime = alarm.when;

        // Only DeskClock is allowed to set this alarm
        if (mNativeData != 0 && mNativeData != -1) {
            if (setPackageName.equals("com.android.deskclock")
                || setPackageName.equals("com.mediatek.schpwronoff")) {//add SchedulePowerOnOff package name
                /// M: Extra Logging @{
                if (DEBUG_ALARM_CLOCK) {
                    Slog.i(TAG, "mBootPackage = " + setPackageName + " set Prop 2");
                }
                ///@}
                SystemProperties.set("persist.sys.bootpackage", "2");
                set(mNativeData, PRE_SCHEDULE_POWER_OFF_ALARM,
                    latestTime / 1000, (latestTime % 1000) * 1000 * 1000);
                SystemProperties.set("sys.power_off_alarm", Long.toString(latestTime / 1000));
            .......
    }

这样就 ok 了,需要注意的是在 8.1 上设置定时开机时间必须大于 120s,否则不会自动开机,据说是新版本的问题,6.0 是没有问题的,无时间限制。

6.0 的 MTK 开关机分析可参考 Android MTK auto power on & off And DeskClock app

开关机简单分析

用户通过 SetAlarm.java PreferenceActivity 来选择开关机时间,最终点击保存调用 saveAlarm()

SchedulePowerOnOff\src\com\mediatek\schpwronoff\SetAlarm.java

private void saveAlarm() {
        final String alert = Alarms.ALARM_ALERT_SILENT;
        mEnabled |= mRepeatPref.mIsPressedPositive;
        Alarms.setAlarm(this, mId, mEnabled, mHour, mMinutes, mRepeatPref.getDaysOfWeek(), true, "", alert);

        if (mEnabled) {
            popAlarmSetToast(this.getApplicationContext(), mHour, mMinutes, mRepeatPref.getDaysOfWeek(), mId);
        }
    }

注意里面的 mId 字段,为 1 表示定时开机,为 2 表示定时关机,通过 setAlarm 来设置"闹钟"

SchedulePowerOnOff\src\com\mediatek\schpwronoff\Alarms.java

public static void setAlarm(Context context, int id, boolean enabled, int hour, int minutes,
            Alarm.DaysOfWeek daysOfWeek, boolean vibrate, String message, String alert) {
        final int initSize = 8;
        ContentValues values = new ContentValues(initSize);
        ContentResolver resolver = context.getContentResolver();
        // Set the alarm_time value if this alarm does not repeat. This will be
        // used later to disable expired alarms.
        long time = 0;
        if (!daysOfWeek.isRepeatSet()) {
            time = calculateAlarm(hour, minutes, daysOfWeek).getTimeInMillis();
        }

        Log.d("@M_" + TAG, "**  setAlarm * idx " + id + " hour " + hour + " minutes " + minutes
                + " enabled " + enabled + " time " + time);

        values.put(Alarm.Columns.ENABLED, enabled ? 1 : 0);
        values.put(Alarm.Columns.HOUR, hour);
        values.put(Alarm.Columns.MINUTES, minutes);
        values.put(Alarm.Columns.ALARM_TIME, time);
        values.put(Alarm.Columns.DAYS_OF_WEEK, daysOfWeek.getCoded());
        values.put(Alarm.Columns.VIBRATE, vibrate);
        values.put(Alarm.Columns.MESSAGE, message);
        values.put(Alarm.Columns.ALERT, alert);
        resolver.update(ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, id), values, null,
                null);

        if (id == 1) {
            // power on
            setNextAlertPowerOn(context);
        } else if (id == 2) {
            // power off
            setNextAlertPowerOff(context);
        }
    }

	private static void enableAlert(Context context, final Alarm alarm, final long atTimeInMillis) {
        if (alarm == null) {
            return;
        }
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Log.d("@M_" + TAG, "** setAlert id " + alarm.mId + " atTime " + atTimeInMillis);
        Intent intent = new Intent(context, com.mediatek.schpwronoff.SchPwrOffReceiver.class);
        Parcel out = Parcel.obtain();
        alarm.writeToParcel(out, 0);
        out.setDataPosition(0);
        intent.putExtra(ALARM_RAW_DATA, out.marshall());
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent,
                PendingIntent.FLAG_CANCEL_CURRENT);
        am.setExact(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
        Calendar c = Calendar.getInstance();
        c.setTime(new java.util.Date(atTimeInMillis));
        Log.d("@M_" + TAG, "Alarms.enableAlertPowerOff(): setAlert id " + alarm.mId + " atTime "
                + c.getTime());
    }

setNextAlertPowerOff 中通过调用 enableAlert(),设置一个 RTC_WAKEUP 时钟,当到设置的关机时间时,SchPwrOffReceiver 广播会被触发,弹出一个 30s 的倒计时提醒用户,点击取消则取消本次定时关机操作,点击确定则立即执行关机操作,关机操作通过隐藏 action ACTION_REQUEST_SHUTDOWN

SchedulePowerOnOff\src\com\mediatek\schpwronoff\ShutdownActivity.java

private void fireShutDown() {
        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
        intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

再回到定时开机操作 enableAlertPowerOn 中

private static void enableAlertPowerOn(Context context, final Alarm alarm,
            final long atTimeInMillis) {
        Log.d("@M_" + TAG, "** setAlert id " + alarm.mId + " atTime " + atTimeInMillis);
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, com.mediatek.schpwronoff.SchPwrOnReceiver.class);
        Parcel out = Parcel.obtain();
        alarm.writeToParcel(out, 0);
        out.setDataPosition(0);
        intent.putExtra(ALARM_RAW_DATA, out.marshall());
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent,
                PendingIntent.FLAG_CANCEL_CURRENT);
        am.setExact(7, atTimeInMillis, sender);
        Calendar c = Calendar.getInstance();
        c.setTime(new java.util.Date(atTimeInMillis));
        Log.d("@M_" + TAG, "Alarms.enableAlertPowerOn(): setAlert id " + alarm.mId + " atTime "
                + c.getTime());
    }

可以看到此处的 setExact 类型变成了 7, 之前的定时关机是** AlarmManager.RTC_WAKEUP**,这个 7 有点来头

frameworks\base\core\java\android\app\AlarmManager.java

/**
     * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC), which will wake up the device when
     * it goes off.
     */
    public static final int RTC_WAKEUP = 0;

	....

	/**
     * M: This alarm type is used to set an alarm that would be triggered if device
     * is in powerOff state. It is set to trigger POWER_OFF_ALARM_BUFFER_TIME ms earlier
     * than the actual alarm time so that phone is in wakeup state when actual alarm
     * triggers
     */
    /** @hide */
    public static final int PRE_SCHEDULE_POWER_OFF_ALARM = 7;

	.....

对应到 MtkAlarmManagerService 中增加要设置的包名,再往下就是 C 中的设置,可参考 Android自动开关机实现

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cczhengv

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

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

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

打赏作者

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

抵扣说明:

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

余额充值