首先对照着Android手机,我们理理清楚需求是什么?
基本需求:
1、 一个手机同一时间只能有一个锁屏实例,但用户可以手动设置不同的锁屏方式。
2、 无论用户怎么摆弄手机,在不知道解锁方式的情况下,不能解锁。
3、 第三方软件可以进行设置自定义的锁屏方式,提供接口。
4、 当系统升级(比如从2.3到4.1时),整体框架不能有大的变动,第三方的接口不变动或者兼容。
与系统交互的需求:
5、 锁屏时和输入法交互,能够对接不同的输入设备和输入法。
6、 锁屏时和接电话交互,电话打入的时候能够不受锁屏影响,但不能通过接听电话绕过锁屏。
7、 锁屏时用户输入反馈,不同解锁的过程中,用户的输入时,锁屏界面会产生不同的变化,让客户知道自己的输入内容。
8、 锁屏时下拉栏的反馈,系统下拉框在某些情况允许下拉,某些不安全情况下不允许下拉。
9、 锁屏时系统按键响应,后台应用是否接受到系统的按键消息可以在代码中控制,
比如也可以在锁屏中播放MP3应用接受按键,点亮或者关闭手电筒,长按红键的系统菜单显示,
短按Power按键,就按下Power按键就直接上锁,再按Power按键,显示亮屏
10、锁屏时的屏幕反馈,用户不操作,一段时间之后,自动灭屏,并上锁,之后,用户操作中,保持屏幕点亮。
11、锁屏时的闹铃处理,来闹铃,闹铃必须再上面。
12、锁屏时需要监控 时间 电池 SIM卡 来电 短信 拥有者这些信息必须实时刷新在锁屏幕的界面上。
看看这些要求,非常的具有挑战性,如果没有Andorid源码实现部分,自己写估计失败的可能性非常大,
但Android的工程师成功的实现了这些功能,我们来看看人家怎么实现的,学习一下。
我们理解的锁屏就是一个窗口,放在了最上面,过滤或者屏蔽各个按键和触摸的事件,在用户特定的输入后,验证通过后,回调关闭窗口,实现解锁。
为了实现锁屏幕的单一实例和高权限的需求,我们必须将这些代码放在Framework中,
Frameworks/base/policy/src/com/android/internal/policy/ impl/
然后我们需要在不同的情形下抽象出那个窗口,先建立一个接口,完成4个功能。
1 可以接受用户的按键输入(当然也可能没有,比如图案解锁) --needsInput
2 可以在某种情况下隐藏界面的处理(比如来电话时) --onPause
3 可以重新显示界面的处理 --onResume
4 可以解锁关闭的处理--cleanUp
public interface KeyguardScreen {
/**
* Return true if your view needs input, so should allow the soft
* keyboard to be displayed.
*/
boolean needsInput();
/**
* This screen is no longer in front of the user.
*/
void onPause();
/**
* This screen is going to be in front of the user.
*/
void onResume();
/**
* This view is going away; a hook to do cleanup.
*/
void cleanUp();
}
那么又有哪些Frame里面的类实现了这个接口呢?
PasswordUnlockScreen --密码锁
PatternUnlockScreen --图案锁
SimPukUnlockScreen --SIM PUK锁
SimUnlockScreen --SIM PIN锁
LockScreen --默认锁
AccountUnlockScreen --帐户锁
以上是简单的窗口,后面再详细的讲,下面接着看我们需要抽象出来的接口,锁屏幕之后,用户不管如何输入,锁屏幕的界面必须同步的反馈用户的输入。
先把函数准备好,只有当用户动作,我们函数才会动作,所以这是一个回调的过程,这个接口叫做KeyguardViewCallback,需要这些接口函数
输入后亮屏幕一段时间 pokeWakelock()
输入后亮屏幕制定时间 pokeWakelock(int millis)
输入完毕,类实现时候自己决定是否成功解锁 keyguardDone()
输入完毕,类实现时候自己决定如何绘制成功解锁界面 keyguardDone()
public interface KeyguardViewCallback {
/**
* Request the wakelock to be poked for the default amount of time.
*/
void pokeWakelock();
/**
* Request the wakelock to be poked for a specific amount of time.
* @param millis The amount of time in millis.
*/
void pokeWakelock(int millis);
/**
* Report that the keyguard is done.
* @param authenticated Whether the user securely got past the keyguard.
* the only reason for this to be false is if the keyguard was instructed
* to appear temporarily to verify the user is supposed to get past the
* keyguard, and the user fails to do so.
*/
void keyguardDone(boolean authenticated);
/**
* Report that the keyguard is done drawing.
*/
void keyguardDoneDrawing();
}
下面看下,一个管理所有视图的管理控制中心类KeyguardViewManager,添加了这个接口的实例
public class KeyguardViewManager implements KeyguardWindowController {
private final static boolean DEBUG = false;
private static String TAG = "KeyguardViewManager";
private final Context mContext;
private final ViewManager mViewManager;
private final KeyguardViewCallback mCallback;
...
}
另外一个关键是KeyguardScreenCallback继承了这个接口,这个接口添加了新的函数,说明了分为两种Screen,一种是LockScreen,一种是UnlockSceen.
通过goToLockScreen()和goToUnlockScreen()两个接口决定转去哪个窗体。
forgotPattern --函数上报忘记图案密码。
isSecure --用户是否安全,如果不需要输入解锁就是不安全(比如滑动解锁),需要输入解锁就是安全的。
recreateme --重新创建自己这个锁屏。
public interface KeyguardScreenCallback extends KeyguardViewCallback {
/**
* Transition to the lock screen.
*/
void goToLockScreen();
/**
* Transition to the unlock screen.
*/
void goToUnlockScreen();
/**
* The user reported that they forgot their pattern (or not, when they want to back out of the
* forgot pattern screen).
*
* @param isForgotten True if the user hit the forgot pattern, false if they want to back out
* of the account screen.
*/
void forgotPattern(boolean isForgotten);
/**
* @return Whether the keyguard requires some sort of PIN.
*/
boolean isSecure();
/**
* @return Whether we are in a mode where we only want to verify the
* user can get past the keyguard.
*/
boolean isVerifyUnlockOnly();
/**
* Stay on me, but recreate me (so I can use a different layout).
*/
void recreateMe(Configuration config);
/**
* Take action to send an emergency call.
*/
void takeEmergencyCallAction();
/**
* Report that the user had a failed attempt to unlock with password or pattern.
*/
void reportFailedUnlockAttempt();
/**
* Report that the user successfully entered their password or pattern.
*/
void reportSuccessfulUnlockAttempt();
/**
* Report whether we there's another way to unlock the device.
* @return true
*/
boolean doesFallbackUnlockScreenExist();
}
在很多需要的界面中都添加了这个接口的实例,而每个界面的构造函数中都有一个参数传入,在构造函数中会保存在当前类的成员变量中,以便控制。这些界面是
SimUnlockScreen
SimPukUnlockScreen
PatternUnlockScreen
PasswordUnlockScreen
下面我们回忆以下,我们抽象出来一个界面接口,加上两个控制回调的接口,以及这些接口是以被其他类实现的还是以成员变量存在于其他类中的。