锁屏(Keyguard)

本文转自:http://blog.csdn.net/qinjuning/article/details/7505703

最近终于成功的摆脱了FM收音机,迈向了新的模块:锁屏、状态栏、Launcher---姑且称之为“IDLE”小组,或许叫手机美容小组,要是能施展下周星星同学的还我漂漂拳,岂不快哉。 OK,闲话打住,咱开始正文。

本文主要内容:

          1、分析锁屏界面的组成 ;

          2、基于源代码分析锁屏相关类 ;

          3、提出一种在框架取消锁屏的方法 。

 

    花了一些时间研究Android原生的锁屏框架---Keyguard,今天就慢慢的讲解下我自己对这个模块的总结,因为目前还处于理论学习的状况,很多细节以及功能上的实现有待后续的补充完整。

    本文分析适合Android2.2和2.3版本,Android4.0尚不清楚。整个锁屏源码基本上完全一样,只是改变了文件存放路径而已。本文分析版本具体是Android2.3版本。

    源文件路径主要有两个:

             frameworks\base\policy\src\com\android\internal\policy\impl\   ---->锁屏框架

             frameworks\base\core\java\com\android\internal\widget\          ----> 提供了一些的自定义View.

 

  一、锁屏界面的组成

 

    通常Android手机上大家常见的界面只有一种,成功后即可解锁进入界面了。其实在Android手机中,正常的锁屏界面由两种不同性质的界面组成:

    第一种界面称之为LockScreen界面(为了叙述方便,我们姑且称为“解锁界面),即我们通常所见到的界面,手机厂商一般定制该界面。界面如下所示:

                                                 

 

    该界面对应自定义View的是LockScreen.java类。

    路径位于:frameworks\policies\base\phone\com\android\internal\policy\impl\LockScreen.java

  

   第二种界面称之为UnLockScreen(为了后文叙述方便,我们姑且称为“开锁界面”),一般由Android源码提供,有如下四种:

    ①、图案开锁界面 ---- PatternUnlockScreen.java类(自定义LinearLayout)

    路径位于:frameworks\policies\base\phone\com\android\internal\policy\impl\PatternUnlockScreen.java

界面显示为:

                                                        

 

    ②、PIN开锁界面 ---- SimUnlockScreen.java 类(自定义LinearLayout)

    路径位于:frameworks\policies\base\phone\com\android\internal\policy\impl\SimUnlockScreen.java

界面显示为:   (图片省略)                           

    ③、密码开锁界面 ---- PasswordUnlockScreen.java类(自定义LinearLayout)

    路径位于:frameworks\policies\base\phone\com\android\internal\policy\impl\PasswordUnlockScreen.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

    其源代码释义如下:

/** 
 * Common interface of each {@link android.view.View}that is a screen of 
 * {@link 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掉 ,即不在需要   
}  

 

    2、KeyguardScreenCallback类  接口

    功能:每个需要显示的界面:LockScreen或者UnLockScreen都保存了该对象的唯一实例,用来向控制界面汇报情况。

    路径:frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardScreenCallback.java

    其源代码释义如下:

/** 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();  //紧急呼叫时的处理行为.   

    /** Report that the user had a failed attempt to unlock with password or pattern.*/  
    void reportFailedUnlockAttempt(); //在UnLockScreen界面登陆失败时处理   

    /** Report that the user successfully entered their password or pattern.*/  
    void reportSuccessfulUnlockAttempt();//在UnLockScreen界面登陆成功时处理   

    /** Report whether we there's another way to unlock the device. 
     * @return true */  
    boolean doesFallbackUnlockScreenExist();  
}  

    其唯一实现类位于LockPatternKeyguardView类的内部类(稍后讲到)。

 

    3、KeyguardViewCallback类  接口

 

    功能: 提供了一些接口用来接受用户操作Screen的结果。

    路径:frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardViewCallback.java

    其源代码释义如下:

/** 
  * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}  
  * various things. 
  */  
public interface KeyguardViewCallback {
     /** 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);//根据给定时间值,使屏幕在该事件段内保持亮屏状况   

    /** 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类 接口

   功能:提供通用 接口,判断该界面是否需要显示输入法窗口。

   其源代码释义如下:

/** 
 * 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. */  
    void setNeedsInput(boolean needsInput);  //是否需要显示输入法,为true表示需要。该方法可以想上层报到是否需要显示输入法窗口   
}  

    其唯一实现类是KeyguardViewManager类(稍后讲到)。

 

    5、KeyguardViewManager类 

    功能:包装了WindowManager功能了,提供了添加、删除锁屏界面的功能。

    其源代码释义如下:     

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卡状态、电池电量;使用广播监听),根据这种状态值的改变回调监听了该状态信息的对象实例。

    其源代码释义如下:     

public class KeyguardUpdateMonitor {  
    ...  
    private int mFailedAttempts = 0;  //当前登录事,已经失败的次数   
    private ArrayList<InfoCallback> mInfoCallbacks; //保存所有监听对象 InfoCallback   
    private ArrayList<SimStateCallback> mSimStateCallbacks ; //保存所有监听对象  SimStateCallback   
    private 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状态   
    }  

    /*** Register to receive notifications about general keyguard information 
     * (see {@link InfoCallback}. */  
    public void registerInfoCallback(InfoCallback callback) {  
        if (!mInfoCallbacks.contains(callback)) {  
            mInfoCallbacks.add(callback);  //注册一个监听器   
        } ...  
    }  
   ...  
 }  

 

转载于:https://www.cnblogs.com/zhouyuchao/archive/2012/08/20/2647926.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值