Android框架浅析之锁屏(Keyguard)机制原理
1、分析锁屏界面的组成 ;
3、提出一种在框架取消锁屏的方法 。
花了一些时间研究 android 原生的锁屏框架---Keyguard,今天就慢慢的讲解下我自己对这个模块的总结,因为目前还处于 理论学习的状况,很多细节以及功能上的实现有待后续的补充完整。
本文分析适合Android2.2和2.3版本,Android4.0尚不清楚。整个锁屏源码基本上完全一样,只是改变了文件存放路径而已。 本文分析版本具体是Android2.3版本。
源文件路径主要有两个:frameworks\base\policy\src\com\android\internal\policy\impl\ ---->锁屏框架
一、锁屏界面的组成
第一种界面称之为LockScreen界面(为了叙述方便,我们姑且称为“解锁界面),即我们通常所见到的界面,手机厂商一般定制该界面。界面如下所示:
①、图案开锁界面 ---- PatternUnlockScreen.java类 (自定义LinearLayout)
路径位于:frameworks\policies\base\phone\com\android\internal\policy\impl\PatternUnlockScreen.java
界面显示为:
②、PIN开锁界面 ---- SimUnlockScreen.java 类 (自定义LinearLayout)
界面显示为: (图片省略)
③、密码开锁界面 ---- PasswordUnlockScreen.java类 (自定义LinearLayout)
路径位于:frameworkspoliciesasephonecomandroidinternalpolicyimplPasswordUnlockScreen.java
④、GoogleAccount 开锁界面 ,即Google账户开锁界面。一般用于当用户输入密码错误次数超过上限值时,系统会提示你输入Google账户去开锁。注意:开启它需要你手动设置账户与同步,否则该界面是不会出来的。对应的源文件是: AccountUnlockScreen.java类 (自定义LinearLayout)
路径位于:frameworks\policies\base\phone\com\android\internal\policy\impl\AccountUnlockScreen.java
界面显示为:
可以按照如下办法选择开启哪一种开锁界面: 设置—>位置和安全—>设置屏幕锁定 ,具体选择那种开锁界面。
显示规则:
当然,这两种界面的组合也是有很多变化的,总的规则如下:首先显示LockScreen界面,接着判断是否开启了UnLockScreen界面,如果设置了UnLockScreen界面,则进入对应的UnLockScreen界面去解锁,才算成功解锁。但,存在一种特殊的情况,就是假如我们选择了图案 UnLockScreen界面,是不会显示LockScreen界面,而只会显示UnLockScreen界面。
二、锁屏界面的实现
我们知道, 任何一种界面都是由各种View/ViewGroup(当然包括自定义的)组成的,然后根据系统对应的状态值的改变去更新
这些View的显示状态,锁屏界面自然也是如此。锁屏界面的实现最顶层是采用了FrameLayout去控制的,当然内部也嵌套了很
多层,内嵌层数的增多的一点好处就是我们可以分开而治,具体针对每层去做相应的更新。难处就是看代码看的很蛋疼。
当界面复杂时,我不得不提Google为开发人员提供的一款优秀工具了---Hierarchy Viewer ,通过它,我们很清晰的弄明白整
个View树的继承层次,一个布局结构,当然,看源代码也是必须的。
关于Hierarchy Viewer的使用请参Android 实用工具Hierarchy Viewer实战。
整个锁屏界面的继承层次如下(部分以及设置了图案开锁界面),更加完整的图请使用Hierarchy Viewer 工具查看。
上图中比较重要的几个视图说明如下:
LockPatternKeyguardView 继承至FrameLayout :作为LockScreen和UnLockScreen的载体,用来控制显示LockScreen还是UnLockScreen界面。
LockScreen 继承至FrameLayout
PatterUnlockScreen ViewGroup类型 : 图案解锁界面
KeyguardViewHost继承至FrameLayout, 该ViewGroup作为顶层View,作为WindowManager的装饰对象添加至窗口。
它和LockPatternKeyguardView关系相当于DecorView和我们Activity内设置的资源布局一样。
三、锁屏机制的类结构说明
看了几天代码,才稍微的理清了下头绪。看完后给我的感觉就是代码之间太BT了,几个类的唯一实例传来传去,太容易混
乱了。接下来我们分析下一些主要的类及其重要的函数,更多函数实现,大家可以自己参考源代码。
PS : 由于这些类的结构图比较简单,因此就没画类图了。主要是从源码角度来分析这些代码逻辑。
1、 KeyguardScreen 类 接口
功能:该接口的主要功能是为每个需要显示的界面:LockScreen或者UnLockScreen定义了四个方法,使其在不同的状态能够
得到相应处理。优点就是: 利用设计原则的面向接口编程,减少对具体对象的依赖。
路径:\frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardScreen.java
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
/** * Common interface of each [url=mailto:%7B@link]{@link[/url] android.view.View} that is a screen of * [url=mailto:%7B@link]{@link[/url] LockPatternKeyguardView}. */ public interface KeyguardScreen {/** Return true if your view needs input, so should allow the soft* keyboard to be displayed. */boolean needsInput(); //View是否需要输入数值,即该界面需要键盘输入数值 /** This screen is no longer in front of the user.*/void onPause();//当该界面不处于前台界面时调用,包括处于GONE或者该界面即将被remove掉/** This screen is going to be in front of the user. */void onResume();//相对于onPause()方法,当该界面不处于前台界面时调用,处于VISIBLE状态时调用/** This view is going away; a hook to do cleanup. */void cleanUp();//该界面即将被remove掉 ,即不在需要 }
功能:每个需要显示的界面:LockScreen或者UnLockScreen都保存了该对象的唯一实例,用来向控制界面汇报情况。
路径:frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardScreenCallback.java
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
/** Within a keyguard, there may be several screens that need a callback * to the host keyguard view. */ public interface KeyguardScreenCallback extends KeyguardViewCallback {/** Transition to the lock screen*/void goToLockScreen(); //当前界面跳转为LockScreen ,而不是UnLockScreen/** Transition to the unlock screen.*/void goToUnlockScreen();//LockScreen成功开锁 ,是否需要显示UnLockScreen,否则,直接开锁成功。//忘记了开锁图案,即我们需要跳转到Google 账户去开锁。void forgotPattern(boolean isForgotten);boolean isSecure();//当前机器是否安全,例如:设置了图案、密码开锁等 //该函数还不太懂,可能是是否只需要验证UnlockScreen界面,即可成功开锁。boolean isVerifyUnlockOnly();/**Stay on me, but recreate me (so I can use a different layout).*/void recreateMe(Configuration config); //重新根据手机当前状态,显示对应的Screen./** Take action to send an emergency call. */void takeEmergencyCallAction(); //紧急呼叫时的处理行为.[/align][align=left] /** Report that the user had a failed attempt to unlock with password or pattern.*/void reportFailedUnlockAttempt(); //在UnLockScreen界面登陆失败时处理[/align][align=left] /** Report that the user successfully entered their password or pattern.*/void reportSuccessfulUnlockAttempt();//在UnLockScreen界面登陆成功时处理[/align][align=left] /** Report whether we there's another way to unlock the device.* [url=home.php?mod=space&uid=7300]@return[/url] true */boolean doesFallbackUnlockScreenExist(); }
其唯一实现类位于LockPatternKeyguardView类的内部类(稍后讲到)。
3、KeyguardViewCallback类 接口
功能: 提供了一些接口用来接受用户操作Screen的结果。
路径:frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardViewCallback.java
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
/*** The callback used by the keyguard view to tell the [url=mailto:%7B@link]{@link[/url] KeyguardViewMediator} * various things.*/ public interface KeyguardViewCallback {[/align][align=left] /** Request the wakelock to be poked for the default amount of time. */void pokeWakelock(); //保存屏幕在一定时间内处于亮屏状况 , 默认时间为5s或者10s/** Request the wakelock to be poked for a specific amount of time. */void pokeWakelock(int millis);//根据给定时间值,使屏幕在该事件段内保持亮屏状况[/align][align=left] /** 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. *///成功的完成开锁,可以进入手机界面了。参数为ture表示是否正大光明的开锁,例如:图案正确,密码输入正确。void keyguardDone(boolean authenticated); /**Report that the keyguard is done drawing. */void keyguardDoneDrawing(); //整个锁屏界面draw()过程绘制完成时,回调该方法. }
其唯一实现类是 KeyguardViewMediator类(稍后讲到)
4、 KeyguardWindowController类 接口
功能:提供通用 接口,判断该界面是否需要显示输入法窗口。
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
/** * Interface passed to the keyguard view, for it to call up to control * its containing window. */ public interface KeyguardWindowController {/** Control whether the window needs input -- that is if it has* text fields and thus should allow input method interaction. *///是否需要显示输入法,为true表示需要。该方法可以想上层报到是否需要显示输入法窗口void setNeedsInput(boolean needsInput); }
其唯一实现类是KeyguardViewManager类(稍后讲到)。
5、KeyguardViewManager类
功能:包装了WindowManager功能了,提供了添加、删除锁屏界面的功能。
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
public class KeyguardViewManager implements KeyguardWindowController {...private WindowManager.LayoutParams mWindowLayoutParams;private boolean mNeedsInput = false; //是否需要输入法 , 默认不需要private FrameLayout mKeyguardHost; //该ViewGroup作为顶层View,作为WindowManager添加至窗口private KeyguardViewBase mKeyguardView; //具体窗口内容。//以上两种的关系相当于DecorView和我们Activity内设置的资源文件一样 private boolean mScreenOn = false; //是否处于亮屏状态//构造函数,初始化各种属性public KeyguardViewManager(Context context, ViewManager viewManager,KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) {...}/*** Helper class to host the keyguard view.*/private static class KeyguardViewHost extends FrameLayout {... //KeyguardViewHost类} /*** Show the keyguard. Will handle creating and attaching to the view manager* lazily.*/ //显示锁屏界面public synchronized void show() { if (mKeyguardHost == null) {...mViewManager.addView(mKeyguardHost, lp);}if (mKeyguardView == null) {...mKeyguardHost.addView(mKeyguardView, lp);if (mScreenOn) {mKeyguardView.onScreenTurnedOn();}}...}/*** Hides the keyguard view */public synchronized void hide() { //隐藏锁屏界面,也就是说我们成功的解锁了if (mKeyguardHost != null) {mKeyguardHost.setVisibility(View.GONE);...}}//锁屏界面是否处于显示状态public synchronized boolean isShowing() {return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);} } }
6、 KeyguardUpdateMonitor.java类
功能:该类的主要功能就是根据监视系统状态值的改变(例如:时间、SIM卡状态、电池电量;使用广播监听),根据这种状态
值的改变回调监听了该状态信息的对象实例。
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
public class KeyguardUpdateMonitor {...private int mFailedAttempts = 0; //当前登录事,已经失败的次数private ArrayList<InfoCallback> mInfoCallbacks; //保存所有监听对象 InfoCallbackprivate ArrayList<SimStateCallback> mSimStateCallbacks ; //保存所有监听对象 SimStateCallbackprivate static class SimArgs { //Sim状态信息 ...}/*** Callback for general information relevant to lock screen.*/interface InfoCallback {//电池电量信息改变:参数含义分别如下:是否显示电量信息 、 是否插入电影充电、 当前电池电量值void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel);void onTimeChanged(); //时间发生了改变//网络运营商状态发生了改变 ,例如从中国移动2G变为中国移动3G,或者无服务等 ;void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn); /** Called when the ringer mode changes. */void onRingerModeChanged(int state);/** 电话状态发生了改变 值可能为:EXTRA_STATE_IDLE、EXTRA_STATE_RINGING、EXTRA_STATE_OFFHOOK*/void onPhoneStateChanged(String newState);}/** Callback to notify of sim state change. */interface SimStateCallback {void onSimStateChanged(IccCard.State simState); //Sim卡信息发生了改变,例如有正常状况变为ABSENT/MISSING状态}[/align][align=left] /*** Register to receive notifications about general keyguard information* (see [url=mailto:%7B@link]{@link[/url] InfoCallback}. */public void registerInfoCallback(InfoCallback callback) {if (!mInfoCallbacks.contains(callback)) {mInfoCallbacks.add(callback); //注册一个监听器 } ...}... }
7, LockPatternKeyguardView类 (自定义ViewGroup)
功能:作为LockScreen和UnLockScreen界面的载体,控制显示哪个界面。
其源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
public class LockPatternKeyguardView extends KeyguardViewBase {...private View mLockScreen;private View mUnlockScreen; private boolean mScreenOn = false;//是否亮屏 enum Mode {//当前显示界面的Mode Lock 或者UnLock }enum UnlockMode {...//开锁界面的几种不同Mode }//构造函数public LockPatternKeyguardView( ...) { //KeyguardScreenCallback的实现对象mKeyguardScreenCallback = new KeyguardScreenCallback() {...};...}public void reset() {...//重置显示界面 }private void recreateLockScreen() {...//重新构建LockScreen }private void recreateUnlockScreen() {...//重新构建UnlockScreen }private void recreateScreens() {...//重新构建该视图 }public void verifyUnlock() {... }public void cleanUp() {... //清理资源对象 }private boolean isSecure() {...//手机设置是否处于安全状态 }private void updateScreen(final Mode mode) {...//根据参数(Lock/unLock),判断显示为LockScreen或者UnlockScreen界面 }View createLockScreen() {...//创建lockScreen }View createUnlockScreenFor(UnlockMode unlockMode) {...//根据不同的Unlock Mode , 创建不同的UnlockScreen }private Mode getInitialMode() {...//得到初始化的状态Mode (lock or unlock). }/** Given the current state of things, what should the unlock screen be? */private UnlockMode getUnlockMode() {...//返回开锁的状态Unlock Mode }private void showTimeoutDialog() {... //输入密码超过一定次数时,提示30s后在登录的对话框 }private void showAlmostAtAccountLoginDialog() {... //显示Google 账户登录对话框 } }
8、KeyguardViewBase类 抽象类 (自定义ViewGroup)
功能:为LockPatternKeyguardView提供了一组通用的方法 。需要值得注意的方法就是他对某些KeyEvent的监听,
当他消费监听到这些KeyEvent,我们的App就监听不到这些KeyEvent了 。常用的有KEYEVENT_VOLUME_UP/DOWN等。
![](/assets/blank.gif)
![](/assets/blank.gif)
public abstract class KeyguardViewBase extends FrameLayout {...@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {...if (interceptMediaKey(event)) {return true;}return super.dispatchKeyEvent(event);} private boolean interceptMediaKey(KeyEvent event) {final int keyCode = event.getKeyCode();if (event.getAction() == KeyEvent.ACTION_DOWN) {switch (keyCode) {...//more keyeventcase KeyEvent.KEYCODE_VOLUME_UP:case KeyEvent.KEYCODE_VOLUME_DOWN: {...// Don't execute default volume behaviorreturn true; //直接返回不在向下传递处理 }}} return false;} }
9、 KeyguardViewProperties.java 接口
功能:提供了创建界面的通用方法。
![](/assets/blank.gif)
![](/assets/blank.gif)
public interface KeyguardViewProperties { //创建一个KeyguardViewBase实例 , 实际是指LockPatternKeyguardView实例 KeyguardViewBase createKeyguardView(Context context,KeyguardUpdateMonitor updateMonitor,KeyguardWindowController controller);[/align][align=left] boolean isSecure();}
其唯一实现类是是LockPatternKeyguardViewProperties类(稍后讲到)。
10、LockPatternKeyguardViewProperties类
源代码释义如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
public class LockPatternKeyguardViewProperties implements KeyguardViewProperties {...//创建一个LockPatternKeyguardView对象public KeyguardViewBase createKeyguardView(Context context,KeyguardUpdateMonitor updateMonitor,KeyguardWindowController controller) {return new LockPatternKeyguardView(context, updateMonitor,mLockPatternUtils, controller);} }
11、KeyguardViewMediator核心类 ,该类是唯一实现了KeyguardViewCallback的类。
功能: 功能:该类提供了一些接口,由PhoneWindowManager)去访问控制Keyguard....
该类的初始化是在PolicyWindowManager的构造函数中创建的。如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
public class PhoneWindowManager implements WindowManagerPolicy {.../** [url=mailto:%7B@inheritDoc]{@inheritDoc[/url]} */ //由SystemServer调用public void init(Context context, IWindowManager windowManager,LocalPowerManager powerManager) {...//初始化该实例mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);}}
参照源代码,把一些重要的属性和方法的大意给分析下:
![](/assets/blank.gif)
![](/assets/blank.gif)
public class KeyguardViewMediator implements KeyguardViewCallback, KeyguardUpdateMonitor.SimStateCallback {private boolean mSystemReady; //启动成功 由SystemServer调用[/size][/font][/align][align=left][font=微软雅黑][size=16px] /**Used to keep the device awake while to ensure the keyguard finishes opening before* we sleep.*/ //在需要显示锁屏界面时,保持屏幕在某个时间段内为暗屏状态 private PowerManager.WakeLock mShowKeyguardWakeLock;private KeyguardViewManager mKeyguardViewManager; //KeyguardViewManager实例/** * External apps (like the phone app) can tell us to disable the keygaurd.*///是否允许其他App禁止锁屏 , 例如来电时 禁止锁屏private boolean mExternallyEnabled = true;//处于锁屏状态 , 即显示锁屏private boolean mShowing = false;// true if the keyguard is hidden by another windowprivate boolean mHidden = false; //被其他窗口掩盖 , 例如来电时锁屏被掩盖private boolean mScreenOn = false; // 是否亮屏[/size][/font][/align][align=left][font=微软雅黑][size=16px] public KeyguardViewMediator(Context context, PhoneWindowManager callback, LocalPowerManager powerManager) {...//构造相关实例对象mKeyguardViewProperties = new LockPatternKeyguardViewProperties(new LockPatternUtils(mContext), mUpdateMonitor);[/size][/font][/align][align=left][size=16px][font=微软雅黑] mKeyguardViewManager = new KeyguardViewManager(context, WindowManagerImpl.getDefault(), this,mKeyguardViewProperties, mUpdateMonitor);//解锁成功后发送的IntentmUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT);mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);}//屏幕变灰暗 , 原因有如下:以及对应的逻辑处理。// 1、OFF_BECAUSE_OF_USER : 用户按下POWER键 , 当前是否处于锁屏界面,若是(mShowing)则重置显示界面,否则重新显示锁屏界面// 2、OFF_BECAUSE_OF_TIMEOUT : 屏幕超时,常见情况就是一段时间没有操作屏幕,手机处于灰暗状态。 处理行为: // 发送Action值为DELAYED_KEYGUARD_ACTION的广播,因为该类注册了该Intent广播,接受到时会调用doKeyguard()方法锁屏// 3、OFF_BECAUSE_OF_PROX_SENSOR:接打电话时,距离感应太近导致暗屏,此时由于PowerManager那儿已经处理了暗屏,不需要做任何事// 最后,如果以上逻辑都不成立,调用 doKeyguard()方法显示屏幕 public void onScreenTurnedOff(int why) {...}/*** Let's us know the screen was turned on.*/public void onScreenTurnedOn() {synchronized (this) {...notifyScreenOnLocked(); //通知亮屏 }}/** Enable the keyguard if the settings are appropriate. */private void doKeyguard() {synchronized (this) {...showLocked();//显示锁屏界面 }}//该方法的调用时机就是当按下POWER键时,系统会回调该方法 keyCode值一般为 26public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) {//操作按键是否能唤醒屏幕 if (isWakeKeyWhenKeyguardShowing(keyCode)) {// give the keyguard view manager a chance to adjust the state of the// keyguard based on the key that woke the device before poking// the wake lockwakeWhenReadyLocked(keyCode);//开始唤醒屏幕咯return true;} else {return false;}}/** [/font][url=mailto:%7B@inheritDoc][font=微软雅黑]{@inheritDoc[/font][/url][font=微软雅黑]} */ //在一定时间内保存屏幕为亮屏状态public void pokeWakelock(int holdMs) {...}//表示成功得分完成了解锁操作public void keyguardDone(boolean authenticated, boolean wakeup) {synchronized (this) {//发送给Handler 进行异步处理Message msg = mHandler.obtainMessage(KEYGUARD_DONE);msg.arg1 = wakeup ? 1 : 0;mHandler.sendMessage(msg);if (authenticated) {mUpdateMonitor.clearFailedAttempts(); //清除错误登录次数 }...}}//Handler对象 , 异步处理private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {... //异步处理 }}};//异步处理完成开锁成功private void handleKeyguardDone(boolean wakeup) { handleHide(); //释放该Keyguard对应的窗口 mWakeLock.release();mContext.sendBroadcast(mUserPresentIntent); //解锁成功,发送Intent信息 }//显示锁屏界面private void handleShow() {synchronized (KeyguardViewMediator.this) {...mKeyguardViewManager.show();mShowing = true;...}}private void handleHide() {synchronized (KeyguardViewMediator.this) {//去除锁屏界面对应的窗口 mKeyguardViewManager.hide();mShowing = false;...}}//设置状态栏enable状态 , 例如:能否被下拉等private void adjustStatusBarLocked() {...// if the keyguard is shown, allow the status bar to open// only if the keyguard is insecure and is covered by another windowboolean enable = !mShowing || (mHidden && !isSecure());mStatusBarManager.disable(enable ?StatusBarManager.DISABLE_NONE : StatusBarManager.DISABLE_EXPAND);}} }
该类的很多方法都是由PhoneWindowManager调用访问的。
基本上把一些重要的类及其相关的方法给走了一遍吧,对看源码的还是很有帮助的。因为我的理解还不是很深入,可能有偏颇的
地方。希望以后能够组件完善起来。 阿门 !
问题:如何在框架中, 解除锁屏 ?
引入:该问题是在CSDN论坛上回答一位网友引发的,最开始由于我也只是简单看了下,因此也就事论事回答了一个小问题。
随着看的越来越深入,慢慢的也在心里长生了涟漪。经过尝试、烧鸡验证,发现如下办法行的通,而且效果还比较好。风险应该
比较小吧。 希望正在在框架修改的同学,慎重行事。
基本思路:毫无疑问,我的想法就是每次需要显示Keyguard---锁屏界面时,我们并不真正的去锁屏,而只是提供了一个空的
方法去给系统调用,让系统觉得我们“锁屏”了,同样也不去真正的隐藏“锁屏”界面,提供一个空壳给系统调用。由于可能涉及
到其它问题,例如:能否下拉状态栏,按下POWER键后,屏幕很快休眠等。Come on ,我们需要统一做处理。
所有步骤函数都发生在KeyguardViewMediator 类中,注释部分为我们所添加的。
Step 1、 取消 真正的去锁屏实现
![](/assets/blank.gif)
![](/assets/blank.gif)
//该方法会显示锁屏界面,我们使其成为一个空壳子 private void handleShow() {synchronized (KeyguardViewMediator.this) {if (DEBUG) Log.d(TAG, "handleShow");if (!mSystemReady) return;[/font][/size][/align][align=left][size=16px][font=微软雅黑] playSounds(true);//Begin : Modifid by qinjuning //mKeyguardViewManager.show(); // //mShowing = true; ////adjustUserActivityLocked(); ////adjustStatusBarLocked(); //取消对状态栏的控制//Endtry {ActivityManagerNative.getDefault().closeSystemDialogs("lock");} catch (RemoteException e) {}mShowKeyguardWakeLock.release();} }
Step 2、 取消 真正的去隐藏锁屏实现
![](/assets/blank.gif)
![](/assets/blank.gif)
//真正的隐藏屏幕实现 private void handleHide() {synchronized (KeyguardViewMediator.this) {if (DEBUG) Log.d(TAG, "handleHide");if (mWakeAndHandOff.isHeld()) {Log.w(TAG, "attempt to hide the keyguard while waking, ignored");return;}// only play "unlock" noises if not on a call (since the incall UI// disables the keyguard)if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {playSounds(false);}//Begin : Modifid by qinjuning //mKeyguardViewManager.hide();//mShowing = false; //adjustUserActivityLocked(); //adjustStatusBarLocked(); //取消对状态栏的控制//End } }
以上两步行动后,存在一个Bug(问题),就是唤醒屏幕后,会在指定的时间内屏幕由亮变暗,我们还需要做如下修改
Step 3、按下POWER键时, 解除屏幕由亮变暗的Bug
![](/assets/blank.gif)
![](/assets/blank.gif)
private void handleWakeWhenReady(int keyCode) {synchronized (KeyguardViewMediator.this) {if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")");[/font][/size][/align][align=left][size=16px][font=微软雅黑] // this should result in a call to 'poke wakelock' which will set a timeout// on releasing the wakelockif (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) {// poke wakelock ourselves if keyguard is no longer activeLog.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves");//Begin : Modifid by qinjuning //pokeWakelock(); //按下POWER键时, 解除屏幕由亮变暗的Bug //End }/*** Now that the keyguard is ready and has poked the wake lock, we can* release the handoff wakelock*/mWakeAndHandOff.release();[/font][/size][/align][align=left][size=16px][font=微软雅黑] if (!mWakeLock.isHeld()) {Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq");}} }
经过真机测试是通过的,但其他风险并不清楚。 这个方法只是提供了一个学习的途径吧。大家慎重行事。
上面Step 1、以及Step 2可以由如下方法代替:
将属性mExternallyEnabled 设置为 false, 接下来需要显示界面时都不会继续走下去,如下函数:
![](/assets/blank.gif)
![](/assets/blank.gif)
/** * Enable the keyguard if the settings are appropriate. */ //显示界面 private void doKeyguard() {synchronized (this) {// if another app is disabling us, don't showif (!mExternallyEnabled) { //mExternallyEnabled 为false if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");[/font][/size][/align][align=left][size=16px][font=微软雅黑] // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes// for an occasional ugly flicker in this situation:// 1) receive a call with the screen on (no keyguard) or make a call// 2) screen times out// 3) user hits key to turn screen back on// instead, we reenable the keyguard when we know the screen is off and the call// ends (see the broadcast receiver below)// TODO: clean this up when we have better support at the window manager level// for apps that wish to be on top of the keyguardreturn;}...} }
该方法的一个缺点就是,假如存在重新调用了setKeyguardEnabled()设置该值,一切都是白搭( 但从源码看,这点不可能出现,因为存在另一个判断依据:变量mNeedToReshowWhenReenabled , 其初始值为false,只有成功禁止锁屏之后才置为(true )。 因此,我们可以仿照这个方法,主动添加一个私有变量,禁止显示锁屏界面,即禁止doKeyguard()方法继续走下去。
OK ,本文到此为止。讲的比较抽象。 大家看代码时多加理解才是王道 。
显然易见,手机厂商,基于框架只需要修改LockScreen这个自定义ViewGroup即可,其他的一套Google已经为我们
封装好了。
在框架层修改肯定不是最好的,对于第三方的App而言,实现不了该功能。还好,SDK为我们提供了接口类去处理隐藏锁屏接口
的方法,该类是KeyguardManager类,关于该类的简介请参考该: KeyguardManager简介
我们可以通过KeyguardManager类实例获得一个KeyguardManager.KeyguardLock对象,进而调用相应方法去取消锁屏界面
和显示锁屏界面。
KeyguardManager.KeyguardLock的两个方法说明如下:
public void disableKeyguard ()
功能:取消锁屏界面显示,同时禁止显示锁屏界面。除非你显示调用了reenableKeyguard()方法使能显示锁屏界面。
public void reenableKeyguard ()功能: 使能显示锁屏界面,如果你之前调用了disableKeyguard()方法取消锁屏界面,那么会马上显示锁屏界面。
这两个方法最终都会调用到KeyguardViewMediator类的setKeyguardEnabled(boolean enable)方法。
参数说明: enable = false 对应于disableKeyguard()方法,
enable = true 对应于reenableKeyguard()方法。
该方法原型为: 位于KeyguardViewMediator类中
![](/assets/blank.gif)
![](/assets/blank.gif)
/** * Same semantics as [url=mailto:%7B@link]{@link[/url] WindowManagerPolicy#enableKeyguard}; provide * a way for external stuff to override normal keyguard behavior. For instance * the phone app disables the keyguard when it receives incoming calls. */ public void setKeyguardEnabled(boolean enabled) {synchronized (this) {mExternallyEnabled = enabled; //保存值,该值会在doKeyguard()时用到,如果为false ,则不进行锁屏[/font][/size][/align][align=left][size=16px][font=微软雅黑] if (!enabled && mShowing) {if (mExitSecureCallback != null) {//该判断为false ... return ;}mNeedToReshowWhenReenabled = true; //置为真,以便下次调用hideLocked(); //已经显示了锁屏界面,则取消隐藏界面} else if (enabled && mNeedToReshowWhenReenabled) { //重新显示锁屏界面mNeedToReshowWhenReenabled = false;[/font][/size][/align][align=left][size=16px][font=微软雅黑] if (mExitSecureCallback != null) {//该判断为false } else {showLocked(); //显示隐藏界面 ...}}} }
使用这两个方法时,记得加上如下权限:android.permission.DISABLE_KEYGUARD
为了在亮屏时,达到取消显示界面的效果,我们还需要知道 一下两个广播:
屏幕变暗以及屏幕点亮的广播
android.intent.action.SCREEN_ON --- 屏幕变亮
android.intent.action.SCREEN_OFF ---- 屏幕点暗
关于这两个广播的说明请参考:http://www.eoeandroid.com/thread-181589-1-1.html
于是在监听到屏幕变暗/变亮时,通过KeyguardManager 类实现即可。对与用户而言,就相当于解除了锁屏界面了。
可能代码如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
//屏幕变暗/变亮的广播 , 我们要调用KeyguardManager类相应方法去解除屏幕锁定private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver(){@Overridepublic void onReceive(Context context , Intent intent) {String action = intent.getAction() ;Log.i(TAG, intent.toString());if(action.equals("android.intent.action.SCREEN_OFF")|| action.equals("android.intent.action.SCREEN_ON") ){mKeyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);mKeyguardLock = mKeyguardManager.newKeyguardLock("zdLock 1"); mKeyguardLock.disableKeyguard();startActivity(zdLockIntent);}}};
最后,可能有些同学在做App时,可能想获取系统的登录次数等,例如:登录失败次数等 ; Android系统已经 为我们提供好了框架去处理,具体对应类是DevicePolicyManager类,关于该类的具体使用请参见该:
http://www.eoeandroid.com/thread-181622-1-1.html
转载于:https://www.cnblogs.com/androidsj/archive/2013/03/11/2953734.html
Android框架浅析之锁屏(Keyguard)机制原理相关推荐
- Android 声音分贝控制锁屏demo实现
标题demo实现总体逻辑: 1. 声明权限 2. 声明,注册 receiver,接收注册设别管理器结果 3. 完成注册APP为设备管理器 4. 录音权限申请 5. 编写类文件,实现业务逻辑 OK,我们 ...
- android 自律软件强制锁屏思路
android 自律软件强制锁屏思路 需求 目前有用的思路 无效的思路 需求 最近在搞一个软件,要实现强制锁屏的功能,实现不能打开其他应用. 目前有用的思路 实现锁屏的思路就是利用一个占满屏幕的悬浮窗 ...
- Android QQ音乐/酷狗音乐锁屏控制实现原理,酷狗锁屏
混乱的锁屏控制 Android自4.0版本, 也就是API level 14开始, 加入了锁屏控制的功能, 相关的类是RemoteControlClient, 这个类在API level 21中被标记 ...
- android代码跳过锁屏,直播app源代码,Android系统移除锁屏功能实现
直播app源代码,Android系统移除锁屏功能实现的相关代码 diff --git a/frameworks/base/packages/SettingsProvider/res/values/de ...
- QQ音乐/酷狗音乐锁屏控制实现原理
我实现的效果 混乱的锁屏控制 Android自4.0版本, 也就是API level 14开始, 加入了锁屏控制的功能, 相关的类是RemoteControlClient, 这个类在API level ...
- Android 7.1.1 锁屏界面启动流程
前几天遇到一个低概率复现锁屏界面不显示,只显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看.前面简单介绍了下Zygote启动流程, Zygote进程启动后会首先创建一个S ...
- android开发笔记之锁屏界面未读短信未接来电提醒(android 4.4)
客户需求 最近在做一个项目,android 4.4系统,客户要求在锁屏界面有未读短信未接来电的提醒功能.而平台没有此功能,要自己实现.并且时间非常紧,---.(其实软件工程师基本上都是这样,坑,坑,坑 ...
- Android 9.0 SystemUI 锁屏流程分析
1.锁屏界面显示的流程 2.按键灭屏 -> 按键亮屏 对于Key事件,InputDispatcher在分发之前会先将事件上发到PhoneWindowManager中,可以进行拦截,故从Phone ...
- android startactivity 跳到锁屏_「瀑布屏」手机到底好不好用?
最近这几年,各大品牌都在围着手机屏幕打转,推陈出新的势头愈演愈烈.而在刘海屏.水滴屏和挖孔屏种种之后,我们又迎来了一个新名词,瀑布屏. 和当初 vivo 与 OPPO 尝试用升降结构隐藏前置摄像头的目 ...
最新文章
- 边工作边刷题:70天一遍leetcode: day 94-1
- python相关 MOOC第一周
- 你不知道LinkedList中的方法
- 气流与路易吉,阿戈,MLFlow,KubeFlow
- c语言做一个小程序报告,《C语言程序设计实践》课程报告30个小程序组合成一个大程序.doc...
- java代码_Java 代码优化
- plsql 存储过程 批量提交_Spring Batch 批量处理策略
- 【今日所得】1.29。。。
- php在类里如何调用call_user_func_array《细说php2》
- 动态规划算法实验报告_动态规划与中心扩展算法
- 10 Seconds Count Down
- thinkphp5 数据库 链接 Connection
- 安装Ubuntu后找不到windows启动项的解决办法
- 王道——数据结构 第一章 思维拓展
- Apache jmeter 压测
- 移动端VUE实现一周课程表
- 三轴试验相关理论知识(1)
- The Top 50 ‘Pictures of the Day’ for 2011
- 亚马逊卖家api_亚马逊如何吸引手工卖家并将其晾干
- Java实现 稀疏矩阵乘积