这两天在搞一个锁屏的小玩意儿,由于时间比较紧,先着重于功能实现,未能从源代码上分析,以下是一些个人的认识与总结,不足或错误之处,还请各位看官批评指正。

1.锁屏页的本质:

Activity,只不过在该Activity上,屏蔽了Home键及Back键的响应,只有当用户解锁的时候才可以进入下一个界面,一般是Launcher界面。当然用户解锁的方式可以是滑动解锁,可以是密码解锁,完全在于自己对该锁屏界面的设计,同样可以像市场上很多锁屏软件一样,可以加入一些有用的小玩意儿,比如天气预报、时钟、新闻等,因为这就是一个Activity,就像平时我们设计界面内容一样,理论上可以随意设计,当然也要符合锁屏页的原则,尽量简洁美观易用。

2.实现原理

        理论上有两种实现方式,一种是定制源代码;另一种就是在应用层开发一个锁屏程序。除非特别需要,一般我们都是自己开发一个锁屏程序。

        如果自己开发一个锁屏程序,一般是这样做的:

(1)系统在按下电源键关闭屏幕或点亮屏幕时会发出相应的广播,如Intent.ACTION_SCREEN_OFF和Intent.ACTION_SCREEN_ON,所以我们就可以注册一个BroadcastReceiver来接收这些广播,应当注意这些广播都是受保护的,是由系统负责发送的。

(2)当接收到这些广播消息,我们就可以启动锁屏页Activity,这样就显示出锁屏界面效果了。

(3)在锁屏页上进行解锁,然后finish掉该锁屏界面,实现解锁效果。这里的要点和难点是屏蔽掉Home键和Back键,下面技术要点里会讲。

3.技术要点

(1)屏蔽Back键

键比较容易屏蔽掉,重写onKeyDown或onBackPressed方法即可,几乎在所有Android版本上都是可以用的(并未亲自测试所有版本,测了几个版本并未遇到无效的情况)。

(2)屏蔽Home键

Home键,这个算是一个难点了。其实可以试想一下,如果运行了一个APP,当Back键和Home键被屏蔽掉,那么这个程序是无法退出的,如果再是一个流氓软件,这是多么恶心的用户体验啊!除非你是一个很正规的锁屏软件,否则不建议屏蔽掉Home键。

Android4.0版本之前还是可以找到方法屏蔽Home键的,但是4.0之后则不再允许屏蔽Home键了,或许Google也是从安全性和用户体验的角度考虑,Home键的响应直接在FrameWork层就处理了,而不会再传到application层来处理。当然网上也看到有方法侦听到Home键,但是监听归监听,但你无法屏蔽它。也就是说4.0之后,当按下Home键时,系统默认会响应启动Home页,也就是Launcher桌面,我们在应用层没有办法再屏蔽它。当然你可以修改FrameWork层代码,重新定制,这属于第一种实现方式了,不在此文的探讨范围。

        下面该是具体实现了:

(2-1) Android 2.2-3.2版本(测试版本2.3.3)

A.重写以下两个方法

@Override  
public boolean onKeyDown(int keyCode, KeyEvent event) {  
    if(KeyEvent.KEYCODE_HOME==keyCode){  
        return true;  
    }  
    return super.onKeyDown(keyCode, event);  
}  
@Override  
 public void onAttachedToWindow(){  
    this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);  
    super.onAttachedToWindow();  
 }

B.加入对应权限

<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>

(2-2)Android4.0版本

        在网上看到如下实现方法:

A.public static final int FLAG_HOMEKEY_DISPATCHED = 0x80000000; 
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.getWindow().setFlags(FLAG_HOMEKEY_DISPATCHED, FLAG_HOMEKEY_DISPATCHED);  
       setContentView(R.layout.main);
    }

B.然后再重写onKey事件。

4.0.4版本可以,4.2.2无效,因此这种方式不能解决4.0+系统屏蔽Home键的根本问题。

Android4.0+,Application层已无法屏蔽Home键,因此只能另想它法。测试了百度锁屏及Go锁屏两款锁屏软件,这两款软件都让用户进行Home设置,避免点击Home键取消锁屏。所谓进行Home设置,其实质就是将该锁屏软件设置为默认的桌面启动页,即Launcher启动桌面,很明显,因为无法屏蔽Home键,我们只能追随它,点击Home启动Launcher,只不过是把Launcher设为我们自己的锁屏App中的一个Activity而已了(其实这里是有技巧的,我开始也理解错了,且看下文)。

 

Go锁屏软件,果断把自己的锁屏页设为Home页,设置方法如下:

<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />    
<category android:name="android.intent.category.DEFAULT" />

Launcher,这时候按下Home键果然就停在锁屏页了,因为此时点Home键本该启动Home页面,而此时我们的锁屏页就是Home页。本以为这样就可以了,但当你解锁后,在其他界面,比如短信界面按下Home键,我们希望回到某个桌面主页(比如系统桌面主页),但是此时却会回到我们锁屏页,因为前面我们把锁屏页设置为默认桌面主页了,而百度锁屏和Go锁屏在点击短信界面的Home时却不会回到锁屏页,而是回到系统主页(这里是可以在百度锁屏里设置的,如果有多个桌面启动Launcher,可以选择)。

    于是猜测可能是锁屏时把锁屏页设为桌面主页,解锁后重新设置了一个桌面主页,于是用百度锁屏解锁后,在应用程序查看,桌面主页依然是锁屏程序而不是在设置里选择的那个桌面启动Launcher。开始有点困惑了,没想通,果断把百度锁屏apk Dec一把,打开其配置文件一看,顿时恍然,也瞬间明白了进行Home键设置时为什么要选择一个解锁后的桌面启动页。

Activity,为了行文方便,姑且记锁屏页为A,记桌面启动页为B。锁屏应用启动后,进行Home设置,实质是将B设置为默认桌面启动页,这里注意的是B的theme是Theme.NoDisplay。关闭屏幕再开启,百度锁屏启动了,点击Home,实质上是启动了B,而B是不可见的,因此不会影响下面的A的操作,然后解锁,显示系统桌面(我在设置里选择了系统桌面),如果再到短信界面按下Home键,其实是启动了B,只是看起来没有反应而已,也不会影响操作,也就不会回到锁屏页了,因为锁屏页A不是桌面页。只有在ScreenOn或ScreenOff时才会启动锁屏。

        再来说前边为什么要我们选择一个解锁后的桌面页,是因为百度锁屏解锁后,会跳到该桌面页,当然我们可以直接使用系统桌面,不用在配置里选择,这样解锁后就跳到系统桌面了。

Activity,就想当然把它设为桌面启动页,因此不能实现百度锁屏的效果;最后自己也另加一个Activity,不过我是使用了一个透明的Activity,并在启动后把它移到后台;在解锁后,默认启动系统桌面,这样就可以完美实现类似百度锁屏的禁用Home键的效果了。原理搞清楚了,实现方法就殊途同归了。