锁屏相关的文件在android对应package:com.android.internal.policy.impl。
phoneWindowManager.java可以派发各种物理key,如Power,Home,Vol+和Vol-等等。那么,这个类是由谁启动的?
在package下Policy.java中
publicPhoneWindowManagermakeNewWindowManager(){
returnnewPhoneWindowManager();
}
这个方法实现创建这个类。而在PolicyManager.java下调用这个方法实现对PhoneWindowManager的创建。
但是,PhoneWindowManager.java中有一个init()方法,这个是这个类的初始化方法,它调用PowerManager、windowManager、KeyguardViewMediator等等实现对PhoneWindowManager。这个Init()是在WindowManagerService.java下的PolicyThread类下得Run方法中调用mPolicy.init(mContext,mService,mPM)。
PhoneWindowManager.java这个类是非常重要的,这里注册了一个Orientation变化的监听类:
MyOrientationListenerextendsWindowOrientationListener,但是,它不能够自动进行更新,它的更新主要是依据接收广播进行的,此处大概就是JNI根据驱动获取相关Sensor消息然后发送消息。这里仅仅粗略说明在这个文件中有屏幕旋转的处理方法。
下面是锁屏的处理流程:
在PhoneWindowManager.java中:
publicvoidsystemReady(){
//tellthekeyguard
mKeyguardMediator.onSystemReady();
android.os.SystemProperties.set("dev.bootcomplete","1");
synchronized(mLock){
updateOrientationListenerLp();
mSystemReady=true;
mHandler.post(newRunnable(){
publicvoidrun(){
updateSettings();
}
});
}
}
这个方法在开机时启动调用,然后mKeyguardMediator.onSystemReady()
在KeyGuardViewMeditor.java是一个非常重要的类,它用来响应电源键的处理(黑亮屏),查询解锁屏等等。
publicvoidonSystemReady(){
synchronized(this){
if(DEBUG)Log.d(TAG,"onSystemReady");
mSystemReady=true; //系统准备好了
doKeyguard(); //判断是否设定了锁
}
}
privatevoiddoKeyguard()主要功能:Enablethekeyguardifthesettingsareappropriate.意思就是如果在Setting里面设置了密码就激活keyguard。
1.如果设置了屏幕锁,黑屏后,在onScreenTurnedOff中doKeyguard()调用一次;
2.如果有SIM卡,且设置了PIN或PUK锁,那么调用doKeyguard();
3.TIMEROUT时调用doKeyguard();
4.接收到消息;DELAYED_KEYGUARD_ACTION或者TelephonyManager.ACTION_PHONE_STATE_CHANGED可能会调用
doKeyguard().
doKeyguard()方法最后调用了showLocked();
privatevoidshowLocked(){
if(DEBUG)Log.d(TAG,"showLocked");
//ensurewestayawakeuntilwearefinisheddisplayingthekeyguard
mShowKeyguardWakeLock.acquire();
Messagemsg=mHandler.obtainMessage(SHOW);
mHandler.sendMessage(msg);
}
实际上就是发送消息显示SHOW
当Handler接收到SHOW这个Message时,进行相关处理:
进入KeyguardViewManager.java:
在publicsynchronizedvoidshow()方法中:
if(mKeyguardView==null){
if(DEBUG)Log.d(TAG,"keyguardviewisnull,creatingit...");
mKeyguardView=mKeyguardViewProperties.createKeyguardView(mContext,mUpdateMonitor,this);
mKeyguardView.setId(R.id.lock_screen);
……
}
mKeyguardView=mKeyguardViewProperties.createKeyguardView(mContext,mUpdateMonitor,this)这个就是KeyguardViewBase创建一个KeyguardViewBase的对象,也就是管理Lock、Unlock画面的类实例。
在Setting里面设置各种锁屏之后,在按power键重新开启时会产生lock或者unlock界面,需要输入密码或者绘出Pattern等操作后才能进入界面。这个锁定和解锁界面是由LockPatternKeyguardView这个类实现的。下面便是这个class的构造函数。
publicLockPatternKeyguardView(
Contextcontext,
KeyguardUpdateMonitorupdateMonitor,
LockPatternUtilslockPatternUtils,
KeyguardWindowControllercontroller)
重要实现:
mConfiguration=context.getResources().getConfiguration();
这个函数是用来获取系统的一些配置,在此用来决定是横屏还是竖屏。
mMode=getInitialMode();
这个则是获取系统的mode了。
mMode是这样的类型:
enumMode{
LockScreen,
UnlockScreen
}
可以初步判断是lock还是unlock状态的flag枚举。获取这个状态是非常重要的,它决定初始化时究竟是显示unlock 界面还是lock界面。
privateModegetInitialMode(){
booleanisPukRequired=false;
for(inti=0;i
isPukRequired=isPukRequired||isSimPukLocked(i);
if(isPukRequired)break;
}
//这里是判断sim是否加入PUK锁或者sim卡不存在
if(stuckOnLockScreenBecauseSimMissing()||isPukRequired){
returnMode.LockScreen;
}else{
//ShowLockScreenfirstforanyscreenotherthanPatternunlock.
finalbooleanusingLockPattern=
mLockPatternUtils.getKeyguardStoredPasswordQuality()==DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
if(isSecure()&&usingLockPattern){
returnMode.UnlockScreen;
}else{
returnMode.LockScreen;
}
}
}
对于isSecure这个函数,定义如下:
privatebooleanisSecure(){
UnlockModeunlockMode=getUnlockMode();
booleansecure=false;
switch(unlockMode){
casePattern:
secure=mLockPatternUtils.isLockPatternEnabled();
break;
caseSimPin:
for(inti=0;i
//CheckifsubscriptionisPIN/PUKlocked.
//isPinLockedreturnstrueifthestateisPIN_REQUIRED/PUK_REQUIRED.
secure=secure||getSimState(i).isPinLocked();
if(secure)break;
}
break;
caseAccount:
secure=true;
break;
casePassword:
secure=mLockPatternUtils.isLockPasswordEnabled();
break;
default:
thrownewIllegalStateException("unknownunlockmode"+unlockMode);
}
returnsecure;
很显然是判断,是否设置了解锁屏方式。是则返回true,否则false。
而usingLockPattern是判断是否是用pattern模式的。具体判断后面研究。
在获取相关初始状态后,就是一些回调函数的实现:
mKeyguardScreenCallback=newKeyguardScreenCallback(),这个是十分容易解决的。
在之后是:
//createboththelockandunlockscreensotheyarequicklyavailable
//whenthescreenturnson
mLockScreen=createLockScreen();
addView(mLockScreen);
finalUnlockModeunlockMode=getUnlockMode();
if(DEBUG)Log.d(TAG,
"LockPatternKeyguardViewctor:abouttocreateUnlockScreenFor;mEnableFallback="
+mEnableFallback);
mUnlockScreen=createUnlockScreenFor(unlockMode);
mUnlockScreenMode=unlockMode;
maybeEnableFallback(context);
addView(mUnlockScreen);
updateScreen(mMode);
由注释可知:其实就是创建lock和unlock界面,这样切换时就可以直接显示而不必先创建在切换,造成时间的缓冲。那么究竟显示lock还是unlock界面就是最后那个调用。具体函数:
privatevoidupdateScreen(finalModemode){
if(DEBUG_CONFIGURATION)Log.v(TAG,"****UPDATESCREEN:mode="+mode
+"lastmode="+mMode,newRuntimeException());
mMode=mode;
//Re-createtheunlockscreenifnecessary.Thisisprimarilyrequiredtoproperlyhandle
//SIMstatechanges.Thistypicallyhappenswhenthismethodiscalledbyreset()
if((mode==Mode.UnlockScreen&&mCurrentUnlockMode!=getUnlockMode())||
(getUnlockMode()==UnlockMode.SimPin)){
recreateUnlockScreen();
}
finalViewgoneScreen=(mode==Mode.LockScreen)?mUnlockScreen:mLockScreen;
finalViewvisibleScreen=(mode==Mode.LockScreen)?mLockScreen:mUnlockScreen;
//dothisbeforechangingvisibilitysofocusisn'trequestedbeforetheinput
//flagisset
mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
if(DEBUG_CONFIGURATION){
Log.v(TAG,"Gone="+goneScreen);
Log.v(TAG,"Visible="+visibleScreen);
}
if(mScreenOn){
if(goneScreen.getVisibility()==View.VISIBLE){
((KeyguardScreen)goneScreen).onPause();
}
if(visibleScreen.getVisibility()!=View.VISIBLE){
((KeyguardScreen)visibleScreen).onResume();
}
}
goneScreen.setVisibility(View.GONE);
visibleScreen.setVisibility(View.VISIBLE);
requestLayout();
if(!visibleScreen.requestFocus()){
thrownewIllegalStateException("keyguardscreenmustbeabletotake"
+"focuswhenshown"+visibleScreen.getClass().getCanonicalName());
}
}
这里mMode=mode;之后
finalViewgoneScreen=(mode==Mode.LockScreen)?mUnlockScreen:mLockScreen;
finalViewvisibleScreen=(mode==Mode.LockScreen)?mLockScreen:mUnlockScreen;
很显然,这是根据mode决定显示lock还是unlock的。
关于在Unlock界面输入错误密码的提示流程:
当用户输入密码时,若不正确,此时就会报告错误:
在PasswordUnlockScreen.java中有一个函数verifyPasswordAndUnlock,如下:
privatevoidverifyPasswordAndUnlock(){
Stringentry=mPasswordEntry.getText().toString();
if(mLockPatternUtils.checkPassword(entry)){
mCallback.keyguardDone(true);
mCallback.reportSuccessfulUnlockAttempt();
}elseif(entry.length()>MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT){
mCallback.reportFailedUnlockAttempt();
//在这里,也就是输入次数是5的整数倍时,弹出报错对话框:
if(0==(mUpdateMonitor.getFailedAttempts()
%LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)){
longdeadline=mLockPatternUtils.setLockoutAttemptDeadline();
handleAttemptLockout(deadline);
}
}
mPasswordEntry.setText("");
}
那么这个错误如何显示的?
上面代码有一处:mCallback.reportFailedUnlockAttempt()
reportFailedUnlockAttempt()函数是在LockPatternKeyguardView.java中,
publicvoidreportFailedUnlockAttempt(){
mUpdateMonitor.reportFailedAttempt();
finalintfailedAttempts=mUpdateMonitor.getFailedAttempts();
finalbooleanusingLockPattern=mLockPatternUtils.getKeyguardStoredPasswordQuality()
==DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
if(usingLockPattern&&mEnableFallback&&failedAttempts==
(LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
-LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)){
showAlmostAtAccountLoginDialog();
}elseif(usingLockPattern&&mEnableFallback
&&failedAttempts>=LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET){
mLockPatternUtils.setPermanentlyLocked(true);
updateScreen(mMode);
}elseif((failedAttempts%LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)
==0){
showTimeoutDialog();
}
mLockPatternUtils.reportFailedPasswordAttempt();
}
showAlmostAtAccountLoginDialog和showTimeoutDialog()决定显示什么样的Message:
privatevoidshowTimeoutDialog(){
//Gettimetolockscreen
inttimeoutInSeconds=(int)LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS/1000;
//Announceamessage
Stringmessage="";
//Getunlockmode
UnlockModeunlockMode=getUnlockMode();
if(unlockMode==UnlockMode.password){
message=mContext.getString(
R.string.lockscreen_too_many_failed_attempts_dialog_message,
mUpdateMonitor.getFailedAttempts(),
timeoutInSeconds);
}
else{
message=mContext.getString(
R.string.lockscreen_too_many_failed_attempts_dialog_message,
mUpdateMonitor.getFailedAttempts(),
timeoutInSeconds);
}
finalAlertDialogdialog=newAlertDialog.Builder(mContext)
.setTitle(null)
.setMessage(message)
.setNeutralButton(R.string.ok,null)
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
if(!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)){
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
dialog.show();
}