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 = ®,
+ },
+ {
+ .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 增加定时开关机的主要内容,如果未能解决你的问题,请参考以下文章