开始
一个多月的 Android 学习,是时候写一些应用了,恰巧我看到少数派中谢了一片文章,推荐了一款时间锁屏软件,于是决定写一个锁屏软件,轻量级的,但是结果还是给了我不小的打击。
过程
废话不多说,先记录下过程,便于以后的拾起。
第一次动手,当然是先收集资料,做好准备工作。通过网络查询得知,锁屏类应用的实现方式有两种:
- 修改锁屏源码,定制自己的锁屏,这样子就没有我后来的问题了,一劳永逸
- 编写锁屏app,做成apk,这是市场上主流锁屏应用采用的方式,但是这样会有很多问题,后续很麻烦
采用第二种方式需要解决几个问题,我根据开发过程中的难易程度,对它们进行了排序,先易后难:
- 屏蔽系统锁屏,用自己的锁屏界面替换系统锁屏
- 自己的锁屏应用不能出现在最近任务列表中
- 屏蔽物理按键,包括Home键、Back键、音量键、Menu或最近任务键等(由于市场上有多个Android系统版本与厂商,会导致按键不同)
- 每次屏幕唤醒、系统开机重启显示自己的锁屏界面
问题一:屏蔽系统锁屏,用自己的锁屏界面替换系统锁屏
最好的方法是引导用户关闭系统锁屏;如果用户不关闭,就在后台使用代码禁用系统锁屏(键盘锁 Keyguard),因为有很多地方都会调用这个功能,所以独立成一个方法:
<span style="font-size:18px;"><span style="font-size:18px;">/**
* 屏蔽系统内置锁屏,待测试
*/
public void CloseSysLock(Context context) {
KeyguardManager mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock mKeyguardLock = mKeyguardManager.newKeyguardLock("ScreenLock");
//这句话需要在manifest文件中添加权限
//<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
mKeyguardLock.disableKeyguard();
}</span></span>
问题二:自己的锁屏应用不能出现在最近任务列表中
这个比较简单,在 manifest 文件中的 Activity 标签中添加属性 android:excludeFromRecents="true"
<span style="font-size:18px;"><!-- 应用不出现在最近任务列表中,android:excludeFromRecents="true" -->
<activity android:name=".MainActivity" android:excludeFromRecents="true"></span>
问题三:屏蔽物理按键,包括Home键、Back键、音量键、Menu或最近任务键等
这里又有两种方法,第一种是利用 Android 的 WindowManager,添加类型为WindowManager.LayoutParams.TYPE_SYSTEM_ERROR 的对话框(View),这个 View 会出现在所有 View 的最顶层,且不会对任何按键做处理,最终达到屏蔽物理按键的作用。贴出参考代码:
<span style="font-size:18px;"><span style="font-size:14px;">WindowManager mWindowManager = getWindowManager();
WindowManager.LayoutParams mLockViewLayoutParams = new WindowManager.LayoutParams();
mLockViewLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
mLockViewLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
//实现关键:添加类型为 WindowManager.LayoutParams.TYPE_SYSTEM_ERROR 的对话框(View)
mLockViewLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
mLockViewLayoutParams.flags = 1280;
View view = View.inflate(this,R.layout.activity_main,null);
mWindowManager.addView(view, mLockViewLayoutParams);
//记得在 Activity 被回收时,删除该 View
//mWindowManager.removeView(view);</span></span>
getWindowManager() 方法是Activity的方法,在其他类中调用,需要有 Activiy的引用。还有,记得在 Activity 被回收时,删除该 View:mWindowManager.removeView(view);
但是,这种方法会屏蔽掉 关机/重启界面,长按 Power 键,关机界面不会弹出,会被遮盖,作为一个强迫症,外加一点完美主义,这是无法容忍的,所以我没有采用这种方法。
第二种方法,是在 Activity 的 onCreate() 方法中,设置 Window 的 Flag,代码如下:
<span style="font-size:18px;"><span style="font-size:14px;">static final int FLAG_HOMEKEY_DISPATCHED = 0x80000000;
getWindow().setFlags(FLAG_HOMEKEY_DISPATCHED, FLAG_HOMEKEY_DISPATCHED)</span></span>
上边的代码用于屏蔽 Home 键,然后重写 onKey() 方法,屏蔽其他物理按键,如下所示:
<span style="font-size:18px;"><span style="font-size:14px;">@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//屏蔽Back、Menu、音量键
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_MENU:
return true;
// case KeyEvent.KEYCODE_HOME:
// Toast.makeText(this, "Home", Toast.LENGTH_SHORT).show();
// return false;
default:
break;
}
return super.onKeyDown(keyCode, event);
}</span></span>
但是,在如今市场上 Android 4.4 及以上版本占主导的情况下,屏蔽 Home 键的代码已经无效,本以为 Home 键与其他物理按键一样,但是测试结果让我很无奈,网上也没有最新的代码与资料。
问题四:每次屏幕唤醒、系统开机重启显示自己的锁屏界面
这个还比较简单,添加三个监听广播(Receiver):ScreenOn、ScreenOff、BootCompleted,在三个Receiver 中分别监听屏幕唤醒、屏幕关闭、系统启动完成,并添加启动 Activity 的代码,为避免重复启动 Activity,我将它的启动模式(launchMode)设置为 singleTask。测试的时候遇到一个异常:
总结
谨以这篇文章做记录,锁屏应用,我还会回来的!