修改Android 休眠逻辑使系统关屏而不进入休眠

近日接到一个比较诡异的产品需求,在我看来需要修改Android PMS。

具体需求如下:

        要求在某一Activity界面在灭屏之后也能监听屏幕的手势事件,在我看来这种手势事件需求应该放在TP的驱动中来完成是最合理的,但是无奈硬件选型已过,而且手势不能完全支持我们的产品需求,无奈放弃底层的思路,开始改上层的电源管理逻辑。

        首先说一下我修改的思路和逻辑,PMS在走休眠流程的时候,判断一下topActivity是不是该特殊需求的Activity,然后再决定走不走常规休眠流程,如果是,则发一个广播给activity,让该activity去持有亮屏的wakelock,同时强行操作背光的亮度节点,直接关屏;不过不是,就走常规的休眠流程喽~~~

        再者,就是上一步提到系统进入休眠的代码段了,一种是PowerKey直接触发,一种是Timeout计时。

下边上我修改的PMS的代码部分:

diff --git a/frameworks/base/services/java/com/android/server/power/PowerManagerService.java b/frameworks/base/services/java/com/android/server/power/PowerManagerService.java
index 8dc0c7a..3e69a57 100755
--- a/frameworks/base/services/java/com/android/server/power/PowerManagerService.java
+++ b/frameworks/base/services/java/com/android/server/power/PowerManagerService.java
@@ -29,6 +29,7 @@ import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;

import android.Manifest;
+import android.content.ComponentName;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -66,6 +67,8 @@ import android.util.TimeUtils;
import android.view.WindowManagerPolicy;
import android.view.Display;

+import android.app.ActivityManager;
+

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -88,6 +91,9 @@ public final class PowerManagerService extends IPowerManager.Stub
implements Watchdog.Monitor {
private static final String TAG = "PowerManagerService";


+ static final String VINCI_MEDIA_PLAY_ACTIVITY = "ConnectActivity";
+ static boolean hasVinciWakelock = false;
+

private static final boolean DEBUG = true;
private static final boolean DEBUG_SPEW = DEBUG && true;

@@ -941,6 +947,8 @@ public final class PowerManagerService extends IPowerManager.Stub
applyWakeLockFlagsOnAcquireLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
+ if (tag != null && tag.contains("VINCI"))
+ hasVinciWakelock = true;

}
}

@@ -1011,6 +1019,8 @@ public final class PowerManagerService extends IPowerManager.Stub
applyWakeLockFlagsOnReleaseLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
+ if (wakeLock.mTag != null && (wakeLock.mTag).contains("VINCI"))
+ hasVinciWakelock = false;

}
}

@@ -1684,6 +1694,8 @@ public final class PowerManagerService extends IPowerManager.Stub

default:
Slog.i(TAG, "Going to sleep by user request...");
reason = PowerManager.GO_TO_SLEEP_REASON_USER;
+
+ if(ifSendNoSleepBroadcast()) return false;

break;
}

@@ -1727,6 +1739,21 @@ public final class PowerManagerService extends IPowerManager.Stub
return true;
}

+ private boolean ifSendNoSleepBroadcast() {
+ ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ ComponentName cn = am.getRunningTasks(Integer.MAX_VALUE).get(0).topActivity;
+ if (null != cn && (cn.getClassName()).contains(VINCI_MEDIA_PLAY_ACTIVITY)) {
+ //not true sleep
+ Intent noSleepAction = new Intent("VINCI_MEDIA_PLAY_NOSLEEP_ACTION");
+ if (mContext != null) {
+ mContext.sendBroadcast(noSleepAction);
+ Log.e(TAG, "======I will send broadcast to top activity.\n");
+ return true;
+ }
+ }
+ return false;
+ }
+

@Override // Binder call
public void nap(long eventTime) {
if (eventTime > SystemClock.uptimeMillis()) {
@@ -1799,18 +1826,22 @@ public final class PowerManagerService extends IPowerManager.Stub

// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
+ Slog.e(TAG, "after updateIsPoweredLocked ======\n");
updateStayOnLocked(mDirty);
+ Slog.e(TAG, "after updateStayOnLocked ======\n");

// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
+ Slog.e(TAG, "updatePowerStateLocked before for loop ======\n");
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;

+ Slog.e(TAG, "in for loop ======\n");
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
@@ -2136,6 +2167,7 @@ else
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
+ Slog.e(TAG, "PMS send MSG_USER_ACTIVITY_TIMEOUT broadcast======\n");
}
} else {
mUserActivitySummary = 0;
@@ -2181,6 +2213,8 @@ else
Slog.d(TAG, "handleUserActivityTimeout");
}

+ if(!hasVinciWakelock && ifSendNoSleepBroadcast()) return;
+

mDirty |= DIRTY_USER_ACTIVITY;
updatePowerStateLocked();
} else {
 

WakeLock申请注册部分:

pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakelock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "VINCI Wakelock");

filter.addAction("VINCI_MEDIA_PLAY_NOSLEEP_ACTION");

将上述三句添加至onCreate方法。

逻辑跟我之前所说的思路吻合, ifSendNoSleepBroadcast()这个方法的目的就是判断是否发送广播的时机,有两处改动中调用了,分别是PowerKey和Timeout两种情况的休眠代码段。hasVinciWakelock该值用来标示当前Activity有没有持有亮屏的wakelock,判断的条件是根据if (wakeLock.mTag != null && (wakeLock.mTag).contains("VINCI"))来,这就要求activity在申请锁的时候添加的tag字段和此处判断一致。

第二部,我们来看activity对屏幕及wake lock的处理逻辑添加。

} else if (mediaAction.equals(action)) {
try {
Process pcs = Runtime.getRuntime().exec("lcd value");

// 获取shell返回流
BufferedInputStream in = new BufferedInputStream(pcs.getInputStream());
// 字符流转换字节流
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// 这里也可以输出文本日志

String lineStr;
while ((lineStr = br.readLine()) != null) {
result = lineStr;
}
br.close();
in.close();

Log.e(TAG, "==================" + result);
if (0 < Integer.valueOf(result).intValue()) {
if (!hasWakelock) {
Runtime.getRuntime().exec("lcd off");
Log.e(TAG, "exec lcd off\n");
mWakelock.acquire();
Log.e(TAG, "have wakelock\n");
hasWakelock = true;
}
} else {
if (hasWakelock) {
Runtime.getRuntime().exec("lcd on");
Log.e(TAG, "exec lcd on\n");
mWakelock.release();
Log.e(TAG, "wakelock release\n");
hasWakelock = false;
}
}
} catch (Exception e) {}
}
这里边涉及对一个lcd脚本的操作,稍后附上该脚本内容,切换屏幕亮度的值结合是否持有wakelock联合判断,因此需要处理脚本返回的亮度值,从而关屏或者恢复关屏之前的亮度值。


最后,附上脚本的内容,lcd命名的脚本,放置system/bin下即可。

#!/system/bin/sh

echo $1

light_path=/sys/class/leds/lcd-backlight/brightness

if [ $1 == "on" ];then
echo "lcd on"
echo 255 > $light_path
elif [ $1 == "off" ];then
echo "lcd off"
echo 0 > $light_path
elif [ $1 == "value" ];then
echo `cat $light_path`
fi
 

核心点:理清PMS休眠的流程逻辑,wakelcok相关操作,最后当然是shell脚本功底了。

补充一点:就是在系统休眠的状态下,app如何唤醒系统电量屏幕。

nWakelock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE _CAUSES_WAKEUP,"screen_on");
nWakelock.acquire();
nWakelock.release();
就这么简单,在需要唤醒的时候按照上述TAG去初始化wakelock,然后来一次申请和释放操作,屏幕就能亮瞎你的狗眼了~~~

备注:

timeout的那种关屏广播可能会导致手指在滑动屏幕的时候就触发(屏幕在有用户事件时突然熄灭),修改的点需要改到updateUserActivitySummaryLocked方法:

在发Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);之前调用下述逻辑:

if (isVinciMediaPlaying() && !isVinciFalseSleep()) {
+ if (0x02 == (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM)) {
+ ifSendNoSleepBroadcast();
+ mUserActivitySummary |= USER_ACTIVITY_SCREEN_BRIGHT;
+ }
+ //return;
+ }


 

大功告成~~~需要联测验证是否能达到需求哦,谨以此文,做工作记录,方便日后查验,供有类似需求的同仁参考。。。

第一章 设计 7 1.1、控制键 8 1.2、鼠标操作 9 1.3、工具栏 10 1.3.1、设计模式工具栏 10 1.3.2、“标准”工具栏 10 1.3.3、“文本”工具栏 11 1.3.4、“边框”工具栏 12 1.3.5、“对齐”工具栏 12 1.4、设计选项 13 1.5、报表设置 15 1.6 页面设置 16 第二章 创建报表 19 2.1、报表对象 20 2.2、“世界,你好!”报表示例 20 2.3、“Text”组件 21 2.4、在“Text”组件中使用HTML标记 23 2.5、通过“Text”组件显示公式 24 2.6、FastReport中的Bands 25 2.7、Data Band 26 2.8、TfrxDBDataSet组件 27 2.9、“客户列表”报表 27 2.10、通过text组件显示数据表字段 29 2.11别名 30 2.12、变量。 30 2.13、“Picture”控件 32 2.14、图形报表 33 2.15、多行文本显示 34 2.16、文本拆分 36 2.17、组件的Wrap 37 2.18、显示数据表中的数据 38 2.19、标签式打印 40 2.20、子bands 42 2.21、组件的移动 43 2.22、两个数据阶的报表(主—细) 43 2.23、页首和页尾数据Band 46 2.24、多页报表 47 第三章 分组集合体 50 3.1、分组打印 51 3.2、其他分组特性 53 3.3页码的重设 55 3.4、组的操作 55 3.5、行数 56 3.6、函数集 57 3.7、页和报表的统计 60 3.8、插入汇总函数 61 第四章 格式化、加强 62 4.1、格式化输出结果 63 4.2、内嵌格式化 63 4.3、条件显示 65 4.4、分行显示数据行的颜色 66 第五章 嵌套报表 68 5.1嵌套报表 69 5.2、设计子报表 69 5.3、子报表中的限制 69 5.4、PrintOnParent选项 70 第六章 脚本 72 6.1、体验脚本语言 73 6.2、脚本结构 76 6.3、“世界你好!”脚本 78 6.4、脚本中组件对象的使用 79 6.5、调用报表变量列表中的变量。 79 6.6、调用数据表子段 80 6.7、脚本中调用汇总函数 80 6.8、报表中变量值的显示 80 6.9、事件 81 6.10、一个使用“OnBeforePrint”事件的例子 82 6.11、在组头打印组的汇总信息 84 6.12、“OnAfterData”事件 88 6.13、Service组件 89 6.13.1、Report组件 89 6.13.2、Engine组件 90 6.13.3、“OutLine”组件 91 6.13.4、引擎组件的使用 91 6.15 Anchors 94 6.16 “Outline” 组件的使用方法 96 6.17 “OnManualBuild” 页面事件 98 6.18 脚本中的组件的建立 104 第七章 交叉报表 106 7.1、创建交叉报表 108 7.2、改变显示 110 7.3、使用函数 112 7.4、对结果进行排序 112 7.5、组合标题的表格 113 7.6、调整单元格的宽度 115 7.7、字体颜色和突出显示 117 7.8、使用脚本语言管理组件 118 7.9、调整行和列的大小 123 7.10、手动填充表格单元 124 7.11、在表格单元中加入其他组件 126 7.12、一些有用的设置 129 第八章 制图表 132 8.1、chart数据中数字的限制 137 8.2、设置 137 8.3、指定数字制表 138 8.4、利用脚本进行制表 139 8.5、在delphi环境中创建的报表的打印 139 第九章 点阵报表 140 9.1、点阵报表使用交叉报表 144 9.2、点阵报表的打印 145 9.3、命令组件 146 第十章 对话框窗体 147 10.1、控件 148 10.2、“世界你好!”报表 149 10.3、输入参数,并传递到报表中 150 10.4、组件的交互 150 10.5、多个对话框表单 151 10.6、对话框窗体的管理 152 第十一章 数据访问组件 155 11.1、组件的描述 156 11.1.1、TfrxDBLookupCombobox组件 157 11.1.2、TfrxADOTable组件 157 11.1.3、TfrxAdoQuery组件 159 11.1.4、TfrxADODatabase组件 161 11.2、创建报表 161 11.3、简单的列表式报表 162 11.4、参数查询报表 163 11.5、其他可用配置 164 第十二章 报表的继承性 166 12.1、创建报表 167 12.2、修改基础模板 169 12.3、组件的继承 170 第十三章 报表向导 171 13.1、新报表向导 172 13.2、数据连接向导 175 13.3、新table向导 176 13.4、新query向导 177 13.5、查询语句生成 177 第十四章 报表的预览 打印 导出 180 14.1、控制键 182 14.2、鼠标控制 182 14.3、报表的打印 183 14.4、报表中的文字搜索 183 14.5、报表的导出 184
这个指南让你熟悉报表设计器和了解报表设计的基本概念(各种区域,数据源,二次表,等等)。指南将帮助你开始用FastReport创建报表,但它不能告诉你怎样使用其它基本的报表设计器。 如果你不熟悉报表设计器,我们建议你参考QuickReport的帮助系统。QuickReport的指南已经包含在你的Delphi拷贝中。QuickReport的大部分基本概念也适用于FastReport,然而,FastReport能提供更多的弹性和最终用户的自定义。 关于FastReport的说明 FastReport是高弹性的报表设计器,用于报表的数据可以从任何类型的数据源获取,包含字符列表,BDE数据库,ADO数据源(不使用BDE),Interbase(使用IBO),Pascal数组和记录,以及一些不常用的数据源。 整个FastReport系统是用Delphi的Pascal编写的。FastReport不需要动态链接库,但需在你的项目中占用大约400kb(Delphi 5)。如果你想最终用户拥有设计能力,这将在你的.EXE中增加大约500kb。虽然这看上去比较大,但这只是其它设计的几分之一。你同样应该考虑到FastReport不仅仅只是包含最终用户更改报表设计的能力,还能够适应查询和数据库的变化。FastReport还包含自己的脚本语言,让应用程序和最终用户能够更容易地改变报表。如果你的大部分应用使用FastReport,你可以简单地配置FastReport BPL(大约1400kb)而所有你的应用程序只需要保留很少的一部分。 你可以发现FastReport有一个非常吸引人的用户界面,使用最新的用户界面组件,例如可停靠的工具栏。你的最终用户将会非常愿意使用这个设计器,只需使用鼠标就可以创建大多数报表。 FastReport是名副其实的快速报表:较其它一些Delphi报表设计器而言,你可以发现没有什么可以接近于它的开发速度。报表预览窗口一直是大多数报表设计器的弱点,高品质的外观,赋于你的应用程序非常专业的用户界面。 FastReport是一个已经拥有三年历史的非常成熟的报表设计器,成长使它拥有其它Delphi报表设计器所不能相比的诸多先进特性。
这个指南让你熟悉报表设计器和了解报表设计的基本概念(各种区域,数据源,二次表,等等)。指南将帮助你开始用FastReport创建报表,但它不能告诉你怎样使用其它基本的报表设计器。 如果你不熟悉报表设计器,我们建议你参考QuickReport的帮助系统。QuickReport的指南已经包含在你的Delphi拷贝中。QuickReport的大部分基本概念也适用于FastReport,然而,FastReport能提供更多的弹性和最终用户的自定义。 关于FastReport的说明 FastReport是高弹性的报表设计器,用于报表的数据可以从任何类型的数据源获取,包含字符列表,BDE数据库,ADO数据源(不使用BDE),Interbase(使用IBO),Pascal数组和记录,以及一些不常用的数据源。 整个FastReport系统是用Delphi的Pascal编写的。FastReport不需要动态链接库,但需在你的项目中占用大约400kb(Delphi 5)。如果你想最终用户拥有设计能力,这将在你的.EXE中增加大约500kb。虽然这看上去比较大,但这只是其它设计的几分之一。你同样应该考虑到FastReport不仅仅只是包含最终用户更改报表设计的能力,还能够适应查询和数据库的变化。FastReport还包含自己的脚本语言,让应用程序和最终用户能够更容易地改变报表。如果你的大部分应用使用FastReport,你可以简单地配置FastReport BPL(大约1400kb)而所有你的应用程序只需要保留很少的一部分。 你可以发现FastReport有一个非常吸引人的用户界面,使用最新的用户界面组件,例如可停靠的工具栏。你的最终用户将会非常愿意使用这个设计器,只需使用鼠标就可以创建大多数报表。 FastReport是名副其实的快速报表:较其它一些Delphi报表设计器而言,你可以发现没有什么可以接近于它的开发速度。报表预览窗口一直是大多数报表设计器的弱点,高品质的外观,赋于你的应用程序非常专业的用户界面。 FastReport是一个已经拥有三年历史的非常成熟的报表设计器,成长使它拥有其它Delphi报表设计器所不能相比的诸多先进特性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值