android 增加定时开关机

Posted 红尘六欲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 增加定时开关机相关的知识,希望对你有一定的参考价值。

定时关机

增加一个系统服务,定时关机相关接口

	private void setPowerOff(Intent intent) {
		boolean enable = intent.getBooleanExtra(VAL_POWEROFF,false);
		Intent inten;
		if(enable) {
			inten = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
			inten.putExtra(Intent.EXTRA_KEY_CONFIRM,false);
			inten.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			mContext.startActivity(inten);
		} else {
		    inten = new Intent(Intent.ACTION_REBOOT);
		    inten.putExtra("nowait", 1);
		    inten.putExtra("interval", 1);
		    inten.putExtra("window", 0);
		    mContext.sendBroadcast(inten);
		}
	}

定时关机app启动调用如下

    public void setTimePowerOff(long time) {
        Log.d(TAG,"time:" + time);
        AlarmManager am = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(ACTION);
        intent.putExtra(CMD_KEY,CMD_ID_POWEROFF);
        intent.putExtra(VAL_POWEROFF,true);//这里这个intent最后广播会调用上面的系统服务setPowerOff
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
                intent, PendingIntent.FLAG_CANCEL_CURRENT);
        am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
    }
      long time =  System.currentTimeMillis() + 10 * 1000;//10秒后关机
      setTimePowerOff(time);

定时关机,实际基本没什么困难。

定时开机

设备外接的rtc芯片为pcf8563,要实现硬件开机,硬件上需要将pcf8563的INT脚接到POWER KEY上,具体硬件具体接法,实际流程是达到设置的时间后pcf8563会将INT脚接低,此时INT接接在POWER KEY上就相当于常按开机键进行开机,开机启动后在清除pcf8563的状态使INT脚变高.
只是提供给特定软件使用,所以增加的不是系统接口,直接使用JNI进行设置定时开机
pcf8563驱动修改

diff --git a/lichee/linux-3.4/drivers/rtc/rtc-pcf8563.c b/lichee/linux-3.4/drivers/rtc/rtc-pcf8563.c
index cd3b4bb..ed4ae78 100755
--- a/lichee/linux-3.4/drivers/rtc/rtc-pcf8563.c
+++ b/lichee/linux-3.4/drivers/rtc/rtc-pcf8563.c
@@ -24,6 +24,9 @@

 #define PCF8563_REG_ST1		0x00 /* status */
 #define PCF8563_REG_ST2		0x01
+#define PCF8563_BIT_AIE		(1 << 1)
+#define PCF8563_BIT_AF		(1 << 3)
+#define PCF8563_BITS_ST2_N	(7 << 5)

 #define PCF8563_REG_SC		0x02 /* datetime */
 #define PCF8563_REG_MN		0x03
@@ -183,10 +186,130 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	return pcf8563_set_datetime(to_i2c_client(dev), tm);
 }

-static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg,
+				   unsigned char length, unsigned char *buf)
 {
+	struct i2c_msg msgs[] = {
+		{/* setup read ptr */
+			.addr = client->addr,
+			.len = 1,
+			.buf = &reg,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = buf
+		},
+	};
+
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int pcf8563_write_block_data(struct i2c_client *client,
+				   unsigned char reg, unsigned char length,
+				   unsigned char *buf)
+{
+	int i, err;
+
+	for (i = 0; i < length; i++) {
+		unsigned char data[2] = { reg + i, buf[i] };
+
+		err = i2c_master_send(client, data, sizeof(data));
+		if (err != sizeof(data)) {
+			dev_err(&client->dev,
+				"%s: err=%d addr=%02x, data=%02x\\n",
+				__func__, err, data[0], data[1]);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
+{
+	unsigned char buf;
+	int err;
+
+	err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
+	if (err < 0)
+		return err;
+
+	if (on)
+		buf |= PCF8563_BIT_AIE;
+	else
+		buf &= ~PCF8563_BIT_AIE;
+
+	buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N);
+
+	err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
+	if (err < 0) {
+		dev_err(&client->dev, "%s: write error\\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
+				  unsigned char *pen)
+{
+	unsigned char buf;
+	int err;
+
+	err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
+	if (err)
+		return err;
+
+	if (en)
+		*en = !!(buf & PCF8563_BIT_AIE);
+	if (pen)
+		*pen = !!(buf & PCF8563_BIT_AF);
+
+	return 0;
+}
+
+static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	unsigned char buf[4];
+	int err;
+	/* The alarm has no seconds, round up to nearest minute */
+	/*if (tm->time.tm_sec) {
+		time64_t alarm_time = rtc_tm_to_time64(&tm->time);
+
+		alarm_time += 60 - tm->time.tm_sec;
+		rtc_time64_to_tm(alarm_time, &tm->time);
+	}*/
+
+	dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d "
+		"enabled=%d pending=%d\\n", __func__,
+		tm->time.tm_min, tm->time.tm_hour, tm->time.tm_wday,
+		tm->time.tm_mday, tm->enabled, tm->pending);
+
+	buf[0] = bin2bcd(tm->time.tm_min);
+	buf[1] = bin2bcd(tm->time.tm_hour);
+	buf[2] = bin2bcd(tm->time.tm_mday);
+	buf[3] = tm->time.tm_wday & 0x07;
+
+	err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf);
+	if (err)
+		return err;
+
+	return pcf8563_set_alarm_mode(client, 1);
 }

 static const struct rtc_class_ops pcf8563_rtc_ops = {
@@ -199,7 +322,7 @@ static int pcf8563_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
 	struct pcf8563 *pcf8563;
-
+	unsigned char alm_pending;
 	int err = 0;

 	dev_dbg(&client->dev, "%s\\n", __func__);
@@ -218,7 +341,16 @@ static int pcf8563_probe(struct i2c_client *client,
 	if (!device_can_wakeup(&client->dev)) { //add by hclydao
 		device_init_wakeup(&client->dev, 1);
 	}
-
+
+	err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);//清除状态
+	if (err) {
+		dev_err(&client->dev, "%s: read error\\n", __func__);
+		return err;
+	}
+
+	if (alm_pending)
+		pcf8563_set_alarm_mode(client, 0);
+		
 	pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
 				&client->dev, &pcf8563_rtc_ops, THIS_MODULE);

应用层jni

JNIEXPORT jint JNICALL Java_com_gzease_hwc_Hwc_setRtcPowerOn(JNIEnv * env, jclass obj,jlong millis)
{
    struct timeval tv;
    int ret;
    struct tm tm, *gmtime_res;
    struct rtc_time rtc;
    int fd;
    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
        return -1;
    }
    tv.tv_sec = (time_t) (millis / 1000LL);
    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
    //LOGD("Setting time of day to sec=%d\\n", (int) tv.tv_sec);
    gmtime_res = gmtime_r(&tv.tv_sec, &tm);
    if (!gmtime_res) {
        LOGE("gmtime_r() failed: %s\\n", strerror(errno));
        return -1;
    }
    memset(&rtc, 0, sizeof(rtc));
    rtc.tm_sec = tm.tm_sec;
    rtc.tm_min = tm.tm_min;
    rtc.tm_hour = tm.tm_hour;
    rtc.tm_mday = tm.tm_mday;
    rtc.tm_mon = tm.tm_mon;
    rtc.tm_year = tm.tm_year;
    rtc.tm_wday = tm.tm_wday;
    rtc.tm_yday = tm.tm_yday;
    rtc.tm_isdst = tm.tm_isdst;
    /*LOGD("setAlarm RTC date/time: %d/%d/%d %02d:%02d:%02d\\n",
        rtc.tm_mday, rtc.tm_mon + 1, rtc.tm_year + 1900,
        rtc.tm_hour, rtc.tm_min, rtc.tm_sec);*/
    fd = open("/dev/rtc0", O_RDONLY|O_NONBLOCK);
    if (fd == -1) {
        LOGE("setRtc open /dev/rtc0 error");
        return -1;
    }
    ret = ioctl(fd, RTC_ALM_SET, &rtc);
    if (ret == -1) {
        LOGE("ioctl RTC_SET_TIME error");
        close(fd);
        return -1;
    }
    close(fd);
    return 0;
}

java层调用

tim =  System.currentTimeMillis() + 60 * 1000;//60秒后开机 最小单位为分钟 不能小于60秒
setTimePowerOn(tim);

同时需要修改/dev/rtc0权限,定时开机设置使用ioctl(fd, RTC_ALM_SET, &rtc)这个会调用到pcf8563驱动中的pcf8563_rtc_set_alarm,当定时时间到后系统启动在pcf8563 probe函数会使用pcf8563_set_alarm_mode清除状态将INT接高.
如果是在系统里加接口有点麻烦,这里就直接用jni进行设置.
参考:
https://blog.csdn.net/zy_style/article/details/53228509?utm_source=blogxgwz9

======================================
作者:hclydao
http://blog.csdn.net/hclydao
版权没有,但是转载请保留此段声明

=======================================

以上是关于android 增加定时开关机的主要内容,如果未能解决你的问题,请参考以下文章

android 增加定时开关机

android 增加定时开关机

定时开关机方案

第十七期新手教程:macOS电脑定时开关机/重启

如何定时让电脑定时关机?

alias,data,系统定时开关机的基本操作