前言
最近有一个需求,要求实现20秒无操作就跳转到一个界面,因为开发初期没有添加BaseActivity,所以再想在APP中实现事件监听就比较难修改。
正文
查阅资料发现可以在framework的ViewRootImpl类的内部类WindowInputEventReceiver的onInputEvent方法中添加广播实现,但是添加后发现会有Sending non-protected broadcast的报错,于是又查阅资料,将添加的广播在AndroidManifest.xml中注册为protected-broadcast:
<protected-broadcast android:name="android.intent.action.xxx" />
添加了之后,又发现非系统应用再点击任何按键时都会闪退,查看报错以及查阅资料发现,protected-broadcast是为了防止三方垃圾应用也发送这些广播,会进行权限检查,不通过时,会抛出一个异常,具体代码在ActivityManagerService中的checkBroadcastFromSystem方法中:
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
// Don't yell about broadcasts sent via shell
return;
}
final String action = intent.getAction();
if (isProtectedBroadcast
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
******
|| AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
// Broadcast is either protected, or it's a public action that
// we've relaxed, so it's fine for system internals to send.
return;
}
******
if (callerApp != null) {
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system " + callerApp.toShortString() + " pkg " + callerPackage,
new Throwable());
} else {
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system uid " + UserHandle.formatUid(callingUid)
+ " pkg " + callerPackage,
new Throwable());
}
}
于是在上面的判断中加入自定义的系统广播,但是验证发现还是会报错:
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.xxx from pid=11072, uid=10013
根据报错信息,找到了对应的代码(ActivityManagerService):
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
******
if (!isCallerSystem) {
if (isProtectedBroadcast) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
******
}
******
}
于是又在isProtectedBroadcast的判断中添加了新增的自定义广播的判断,再验证就没问题了。
综上,要添加一个自定义的系统广播,首先要在frameworksbasecoreresAndroidManifest.xml中注册成protected-broadcast,然后需要在ActivityManagerService中添加判断;这样才能在framework中使用这个广播。
最后,可以根据具体需求,看是否要添加到Intent类中作为常量,比如需求提供给第三方SDK时,可以添加一下。
注意:这种方式添加的自定义系统广播,任何应用都可以发送相同的广播(与protected-broadcast设计初衷背道而驰),所以不适用于非常精准和严谨的情况。
后记
单纯是20秒无操作,也许还有其它的实现思路,这里结合自己查到的资料提一下,因为InputEvent的直接子类只有MotionEvent以及KeyEvent,对应了按键输入和“点触”设备输入,所以也可以利用这两点来解决,可能会稍微复杂一点,工作要注意效率,故未深入研究,这里说出思路供有相似需求的小伙伴参考:
PointerEventDispatcher类及PointerEventListener接口可以实现触摸以及鼠标点击等touch事件的监听,但是也需要在framework做修改KeyEvent老生常谈,可以在PhoneWindowManager做处理
最后
以上就是迷路眼睛最近收集整理的关于Android P添加自定义系统广播的全部内容,更多相关Android内容请搜索靠谱客的其他文章。
发表评论 取消回复