• Android框架浅析之锁屏(Keyguard)机制原理


    最近终于成功的摆脱了FM收音机,迈向了新的模块:锁屏、状态栏、Launcher---姑且称之为“IDLE”小组,或许叫手机

     美容小组,要是能施展下周星星同学的还我漂漂拳,岂不快哉。 OK,闲话打住,咱开始正文。

        

          本文主要内容:

     

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

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

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

     

          花了一些时间研究Android原生的锁屏框架---Keyguard,今天就慢慢的讲解下我自己对这个模块的总结,因为目前还处于

      理论学习的状况,很多细节以及功能上的实现有待后续的补充完整。

     

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

         本文分析版本具体是Android2.3版本。

     

         源文件路径主要有两个:

                 frameworksasepolicysrccomandroidinternalpolicyimpl   ---->锁屏框架

                 frameworksasecorejavacomandroidinternalwidget          ----> 提供了一些的自定义View.

     

      一、锁屏界面的组成

     

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

     两种不同性质的界面组成:

     

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

              该界面。界面如下所示:

                                                     

     

     

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

               路径位于:frameworkspoliciesasephonecomandroidinternalpolicyimplLockScreen.java

                   

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

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

                          路径位于:frameworkspoliciesasephonecomandroidinternalpolicyimplPatternUnlockScreen.java

                          界面显示为:

                                                            

     

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

                          路径位于:frameworkspoliciesasephonecomandroidinternalpolicyimplSimUnlockScreen.java

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

                                                 

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

     

                          路径位于:frameworkspoliciesasephonecomandroidinternalpolicyimplPasswordUnlockScreen.java

                          界面显示为:

                                                  

     

                 ④、GoogleAccount 开锁界面 ,即Google账户开锁界面。一般用于当用户输入密码错误次数超过上限值时,系统会提示

           你输入Google账户去开锁。注意:开启它需要你手动设置账户与同步,否则该界面是不会出来的。

                        对应的源文件是: AccountUnlockScreen.java类    (自定义LinearLayout)

                        路径位于:frameworkspoliciesasephonecomandroidinternalpolicyimplAccountUnlockScreen.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定义了四个方法,使其在不同的状态能够

              得到相应处理。优点就是:   利用设计原则的面向接口编程,减少对具体对象的依赖。

          路径:frameworksasepolicysrccomandroidinternalpolicyimplKeyguardScreen.java

         其源代码释义如下:

     

    1. /** 
    2.  * Common interface of each {@link android.view.View} that is a screen of 
    3.  * {@link LockPatternKeyguardView}. 
    4.  */   
    5. public interface KeyguardScreen {  
    6.     /** Return true if your view needs input, so should allow the soft 
    7.      * keyboard to be displayed. */  
    8.     boolean needsInput(); //View是否需要输入数值,即该界面需要键盘输入数值   
    9.     /** This screen is no longer in front of the user.*/  
    10.     void onPause();//当该界面不处于前台界面时调用,包括处于GONE或者该界面即将被remove掉  
    11.     /** This screen is going to be in front of the user. */  
    12.     void onResume();//相对于onPause()方法,当该界面不处于前台界面时调用,处于VISIBLE状态时调用  
    13.     /** This view is going away; a hook to do cleanup. */  
    14.     void cleanUp();//该界面即将被remove掉 ,即不在需要  
    15. }  
    /**
     * 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都保存了该对象的唯一实例,用来向控制界面汇报情况。

          路径:frameworksasepolicysrccomandroidinternalpolicyimplKeyguardScreenCallback.java

           其源代码释义如下:

     

    1. /** Within a keyguard, there may be several screens that need a callback 
    2.  * to the host keyguard view. 
    3.  */   
    4. public interface KeyguardScreenCallback extends KeyguardViewCallback {  
    5.     /** Transition to the lock screen*/  
    6.     void goToLockScreen();  //当前界面跳转为LockScreen ,而不是UnLockScreen  
    7.     /** Transition to the unlock screen.*/  
    8.     void goToUnlockScreen();//LockScreen成功开锁 ,是否需要显示UnLockScreen,否则,直接开锁成功。  
    9.     //忘记了开锁图案,即我们需要跳转到Google 账户去开锁。  
    10.     void forgotPattern(boolean isForgotten);  
    11.     boolean isSecure();//当前机器是否安全,例如:设置了图案、密码开锁等     
    12.     //该函数还不太懂,可能是是否只需要验证UnlockScreen界面,即可成功开锁。  
    13.     boolean isVerifyUnlockOnly();  
    14.     /**Stay on me, but recreate me (so I can use a different layout).*/  
    15.     void recreateMe(Configuration config); //重新根据手机当前状态,显示对应的Screen.  
    16.     /** Take action to send an emergency call. */  
    17.     void takeEmergencyCallAction();  //紧急呼叫时的处理行为.  
    18.   
    19.     /** Report that the user had a failed attempt to unlock with password or pattern.*/  
    20.     void reportFailedUnlockAttempt(); //在UnLockScreen界面登陆失败时处理  
    21.   
    22.     /** Report that the user successfully entered their password or pattern.*/  
    23.     void reportSuccessfulUnlockAttempt();//在UnLockScreen界面登陆成功时处理  
    24.   
    25.     /** Report whether we there's another way to unlock the device. 
    26.      * @return true */  
    27.     boolean doesFallbackUnlockScreenExist();  
    28. }  
    /** 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的结果。

             路径:frameworksasepolicysrccomandroidinternalpolicyimplKeyguardViewCallback.java

             其源代码释义如下:

     

    1. /** 
    2.   * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}  
    3.   * various things. 
    4.   */  
    5.  public interface KeyguardViewCallback {  
    6.   
    7.      /** Request the wakelock to be poked for the default amount of time. */  
    8.      void pokeWakelock();  //保存屏幕在一定时间内处于亮屏状况 , 默认时间为5s或者10s  
    9.      /** Request the wakelock to be poked for a specific amount of time.  */  
    10.      void pokeWakelock(int millis);//根据给定时间值,使屏幕在该事件段内保持亮屏状况  
    11.   
    12.      /** Report that the keyguard is done. 
    13.       * @param authenticated Whether the user securely got past the keyguard. 
    14.       *   the only reason for this to be false is if the keyguard was instructed 
    15.       *   to appear temporarily to verify the user is supposed to get past the 
    16.       *   keyguard, and the user fails to do so. */  
    17.      //成功的完成开锁,可以进入手机界面了。参数为ture表示是否正大光明的开锁,例如:图案正确,密码输入正确。  
    18.      void keyguardDone(boolean authenticated);   
    19.      /**Report that the keyguard is done drawing. */  
    20.      void keyguardDoneDrawing(); //整个锁屏界面draw()过程绘制完成时,回调该方法.  
    21.  }  
    /**
      * 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类 接口

     

     

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

             其源代码释义如下:

     

    1. /** 
    2.  * Interface passed to the keyguard view, for it to call up to control 
    3.  * its containing window. 
    4.  */  
    5. public interface KeyguardWindowController {  
    6.     /** Control whether the window needs input -- that is if it has 
    7.      * text fields and thus should allow input method interaction. */  
    8.     void setNeedsInput(boolean needsInput);  //是否需要显示输入法,为true表示需要。该方法可以想上层报到是否需要显示输入法窗口  
    9. }  
    /**
     * 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功能了,提供了添加、删除锁屏界面的功能。

              其源代码释义如下:     

     

    1.  public class KeyguardViewManager implements KeyguardWindowController {  
    2.      ...  
    3.      private WindowManager.LayoutParams mWindowLayoutParams;  
    4.      private boolean mNeedsInput = false//是否需要输入法 , 默认不需要  
    5.   
    6.      private FrameLayout mKeyguardHost;   //该ViewGroup作为顶层View,作为WindowManager添加至窗口  
    7.      private KeyguardViewBase mKeyguardView; //具体窗口内容。  
    8.      //以上两种的关系相当于DecorView和我们Activity内设置的资源文件一样  
    9.   
    10.      private boolean mScreenOn = false//是否处于亮屏状态  
    11.      //构造函数,初始化各种属性  
    12.      public KeyguardViewManager(Context context, ViewManager viewManager,  
    13.              KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) {  
    14.         ...  
    15.      }  
    16.      /** 
    17.       * Helper class to host the keyguard view. 
    18.       */  
    19.      private static class KeyguardViewHost extends FrameLayout {  
    20.          ... //KeyguardViewHost类  
    21.      }  
    22.   
    23.      /** 
    24.       * Show the keyguard.  Will handle creating and attaching to the view manager 
    25.       * lazily. 
    26.       */  //显示锁屏界面  
    27.      public synchronized void show() {         
    28.          if (mKeyguardHost == null) {  
    29.              ...  
    30.              mViewManager.addView(mKeyguardHost, lp);  
    31.          }  
    32.          if (mKeyguardView == null) {  
    33.              ...  
    34.              mKeyguardHost.addView(mKeyguardView, lp);  
    35.              if (mScreenOn) {  
    36.                  mKeyguardView.onScreenTurnedOn();  
    37.              }  
    38.          }  
    39.         ...  
    40.      }  
    41.      ...  
    42.   
    43.      /*** Hides the keyguard view */  
    44.      public synchronized void hide() { //隐藏锁屏界面,也就是说我们成功的解锁了  
    45.          if (mKeyguardHost != null) {  
    46.              mKeyguardHost.setVisibility(View.GONE);  
    47.                  ...  
    48.              }  
    49.      }  
    50.      //锁屏界面是否处于显示状态  
    51.      public synchronized boolean isShowing() {  
    52.          return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);  
    53.      }  
    54.  }  
    55.   
    56.   
    57. }  
    58.         
     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卡状态、电池电量;使用广播监听),根据这种状态

               值的改变回调监听了该状态信息的对象实例。

           其源代码释义如下:     

     

    1. public class KeyguardUpdateMonitor {  
    2.     ...  
    3.     private int mFailedAttempts = 0;  //当前登录事,已经失败的次数  
    4.     private ArrayList<InfoCallback> mInfoCallbacks; //保存所有监听对象 InfoCallback  
    5.     private ArrayList<SimStateCallback> mSimStateCallbacks ; //保存所有监听对象  SimStateCallback  
    6.     private static class SimArgs {  //Sim状态信息  
    7.       ...  
    8.     }  
    9.     /** 
    10.      * Callback for general information relevant to lock screen. 
    11.      */  
    12.     interface InfoCallback {  
    13.         //电池电量信息改变:参数含义分别如下:是否显示电量信息  、 是否插入电影充电、 当前电池电量值  
    14.         void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel);  
    15.         void onTimeChanged(); //时间发生了改变  
    16.         //网络运营商状态发生了改变 ,例如从中国移动2G变为中国移动3G,或者无服务等 ;  
    17.         void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn);   
    18.         /** Called when the ringer mode changes. */  
    19.         void onRingerModeChanged(int state);  
    20.         /** 电话状态发生了改变  值可能为:EXTRA_STATE_IDLE、EXTRA_STATE_RINGING、EXTRA_STATE_OFFHOOK*/  
    21.         void onPhoneStateChanged(String newState);  
    22.     }  
    23.     /** Callback to notify of sim state change. */  
    24.     interface SimStateCallback {  
    25.         void onSimStateChanged(IccCard.State simState); //Sim卡信息发生了改变,例如有正常状况变为ABSENT/MISSING状态  
    26.     }  
    27.   
    28.     /*** Register to receive notifications about general keyguard information 
    29.      * (see {@link InfoCallback}. */  
    30.     public void registerInfoCallback(InfoCallback callback) {  
    31.         if (!mInfoCallbacks.contains(callback)) {  
    32.             mInfoCallbacks.add(callback);  //注册一个监听器  
    33.         } ...  
    34.     }  
    35.    ...  
    36.  }  
    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);  //注册一个监听器
            } ...
        }
       ...
     }

     

     

         7, LockPatternKeyguardView类  (自定义ViewGroup)

     

               功能:作为LockScreen和UnLockScreen界面的载体,控制显示哪个界面。

                 其源代码释义如下:     

     

    1. public class LockPatternKeyguardView extends KeyguardViewBase {  
    2.     ...  
    3.     private View mLockScreen;  
    4.     private View mUnlockScreen;  
    5.   
    6.     private boolean mScreenOn = false;//是否亮屏  
    7.   
    8.     enum Mode {  
    9.         //当前显示界面的Mode Lock 或者UnLock  
    10.     }  
    11.     enum UnlockMode {  
    12.         ...//开锁界面的几种不同Mode   
    13.     }  
    14.     //构造函数  
    15.     public LockPatternKeyguardView( ...) {       
    16.         //KeyguardScreenCallback的实现对象  
    17.         mKeyguardScreenCallback = new KeyguardScreenCallback() {  
    18.            ...  
    19.         };  
    20.         ...  
    21.     }  
    22.     public void reset() {  
    23.        ...//重置显示界面  
    24.     }  
    25.     private void recreateLockScreen() {  
    26.     ...//重新构建LockScreen  
    27.     }  
    28.     private void recreateUnlockScreen() {  
    29.        ...//重新构建UnlockScreen  
    30.     }  
    31.     private void recreateScreens() {  
    32.        ...//重新构建该视图  
    33.     }  
    34.     public void verifyUnlock() {  
    35.        ...   
    36.     }  
    37.     public void cleanUp() {  
    38.     ... //清理资源对象  
    39.     }  
    40.     private boolean isSecure() {  
    41.        ...//手机设置是否处于安全状态  
    42.     }  
    43.     private void updateScreen(final Mode mode) {  
    44.        ...//根据参数(Lock/unLock),判断显示为LockScreen或者UnlockScreen界面  
    45.     }  
    46.     View createLockScreen() {  
    47.     ...//创建lockScreen  
    48.     }  
    49.     View createUnlockScreenFor(UnlockMode unlockMode) {  
    50.        ...//根据不同的Unlock Mode , 创建不同的UnlockScreen  
    51.     }  
    52.     private Mode getInitialMode() {  
    53.        ...//得到初始化的状态Mode (lock or unlock).  
    54.     }  
    55.     /** Given the current state of things, what should the unlock screen be? */  
    56.     private UnlockMode getUnlockMode() {  
    57.        ...//返回开锁的状态Unlock Mode  
    58.     }  
    59.     private void showTimeoutDialog() {  
    60.         ... //输入密码超过一定次数时,提示30s后在登录的对话框  
    61.     }  
    62.     private void showAlmostAtAccountLoginDialog() {  
    63.        ... //显示Google 账户登录对话框  
    64.     }  
    65. }  
     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等。

     

    1. public abstract class KeyguardViewBase extends FrameLayout {  
    2.      ...  
    3.   @Override  
    4.     public boolean dispatchKeyEvent(KeyEvent event) {  
    5.         ...  
    6.         if (interceptMediaKey(event)) {  
    7.             return true;  
    8.         }  
    9.         return super.dispatchKeyEvent(event);  
    10.     }  
    11.   
    12.     private boolean interceptMediaKey(KeyEvent event) {  
    13.         final int keyCode = event.getKeyCode();  
    14.         if (event.getAction() == KeyEvent.ACTION_DOWN) {  
    15.             switch (keyCode) {  
    16.                 ...//more keyevent  
    17.                 case KeyEvent.KEYCODE_VOLUME_UP:  
    18.                 case KeyEvent.KEYCODE_VOLUME_DOWN: {  
    19.                     ...  
    20.                     // Don't execute default volume behavior  
    21.                     return true//直接返回不在向下传递处理  
    22.                 }  
    23.             }  
    24.         }   
    25.         return false;  
    26.     }  
    27.  }  
    public abstract class KeyguardViewBase extends FrameLayout {
    	 ...
      @Override
        public 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 keyevent
                    case KeyEvent.KEYCODE_VOLUME_UP:
                    case KeyEvent.KEYCODE_VOLUME_DOWN: {
                        ...
                        // Don't execute default volume behavior
                        return true; //直接返回不在向下传递处理
                    }
                }
            } 
            return false;
        }
     }

     

       9、 KeyguardViewProperties.java 接口

                     功能:提供了创建界面的通用方法。

     

    1.   public interface KeyguardViewProperties {    
    2.     //创建一个KeyguardViewBase实例 , 实际是指LockPatternKeyguardView实例  
    3.     KeyguardViewBase createKeyguardView(Context context,  
    4.             KeyguardUpdateMonitor updateMonitor,  
    5.             KeyguardWindowController controller);  
    6.   
    7.     boolean isSecure();  
    8. }  
       public interface KeyguardViewProperties {  
    	    //创建一个KeyguardViewBase实例 , 实际是指LockPatternKeyguardView实例
    	    KeyguardViewBase createKeyguardView(Context context,
    	            KeyguardUpdateMonitor updateMonitor,
    	            KeyguardWindowController controller);
    
    	    boolean isSecure();
    	}

                    

     

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

     

      10、LockPatternKeyguardViewProperties类 

                    源代码释义如下:

     

    1. public class LockPatternKeyguardViewProperties implements KeyguardViewProperties {  
    2.    ...  
    3.    //创建一个LockPatternKeyguardView对象  
    4.    public KeyguardViewBase createKeyguardView(Context context,  
    5.            KeyguardUpdateMonitor updateMonitor,  
    6.            KeyguardWindowController controller) {  
    7.        return new LockPatternKeyguardView(context, updateMonitor,  
    8.                mLockPatternUtils, controller);  
    9.    }  
     public class LockPatternKeyguardViewProperties implements KeyguardViewProperties {
        ...
        //创建一个LockPatternKeyguardView对象
        public KeyguardViewBase createKeyguardView(Context context,
                KeyguardUpdateMonitor updateMonitor,
                KeyguardWindowController controller) {
            return new LockPatternKeyguardView(context, updateMonitor,
                    mLockPatternUtils, controller);
        }
    }

      //=============================================

     

      //  OK ,我知道你看的很纠结了,具体需要时参考源代码看是最明智的。

      //=============================================

     

        我知道代码贴的太多了,没办法,谁让它理解起来就那么费劲呢 ? 你可别犯愁,真正核心的类可还没出来。。

     

        12、KeyguardViewMediator核心类 ,该类是唯一实现了KeyguardViewCallback的类。

               功能:  功能:该类提供了一些接口,由PhoneWindowManager)去访问控制Keyguard.... 

               该类的初始化是在PolicyWindowManager的构造函数中创建的。如下:

     

    1. public class PhoneWindowManager implements WindowManagerPolicy {  
    2.    ...  
    3.   /** {@inheritDoc} */  //由SystemServer调用  
    4.   public void init(Context context, IWindowManager windowManager,  
    5.           LocalPowerManager powerManager) {  
    6.       ...//初始化该实例  
    7.       mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);  
    8.   }  
    9.  }  
    10.    
     public class PhoneWindowManager implements WindowManagerPolicy {
    	   ...
    	  /** {@inheritDoc} */  //由SystemServer调用
    	  public void init(Context context, IWindowManager windowManager,
    	          LocalPowerManager powerManager) {
    	      ...//初始化该实例
    	      mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
    	  }
      }
      

     

           参照源代码,把一些重要的属性和方法的大意给分析下:  

    1. public class KeyguardViewMediator implements KeyguardViewCallback, KeyguardUpdateMonitor.SimStateCallback {  
    2.     private boolean mSystemReady;  //启动成功 由SystemServer调用  
    3.   
    4.     /**Used to keep the device awake while to ensure the keyguard finishes opening before 
    5.      * we sleep.*/ //在需要显示锁屏界面时,保持屏幕在某个时间段内为暗屏状态    
    6.     private PowerManager.WakeLock mShowKeyguardWakeLock;  
    7.     private KeyguardViewManager mKeyguardViewManager; //KeyguardViewManager实例  
    8.     /**  * External apps (like the phone app) can tell us to disable the keygaurd.*/  
    9.     //是否允许其他App禁止锁屏 , 例如来电时 禁止锁屏  
    10.     private boolean mExternallyEnabled = true;  
    11.     //处于锁屏状态 , 即显示锁屏  
    12.     private boolean mShowing = false;  
    13.     // true if the keyguard is hidden by another window  
    14.     private boolean mHidden = false//被其他窗口掩盖 , 例如来电时锁屏被掩盖  
    15.     private boolean mScreenOn = false// 是否亮屏  
    16.   
    17.     public KeyguardViewMediator(Context context, PhoneWindowManager callback,  
    18.             LocalPowerManager powerManager) {  
    19.         ...  
    20.         //构造相关实例对象  
    21.         mKeyguardViewProperties = new LockPatternKeyguardViewProperties(  
    22.                 new LockPatternUtils(mContext), mUpdateMonitor);  
    23.   
    24.         mKeyguardViewManager = new KeyguardViewManager(  
    25.                 context, WindowManagerImpl.getDefault(), this,  
    26.                 mKeyguardViewProperties, mUpdateMonitor);  
    27.         //解锁成功后发送的Intent  
    28.         mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT);  
    29.         mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);  
    30.     }  
    31.     /** Called to let us know the screen was turned off. 
    32.      *   @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, 
    33.      *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or 
    34.      *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}. 
    35.      */  
    36.     //屏幕变灰暗  , 原因有如下:以及对应的逻辑处理。  
    37.     // 1、OFF_BECAUSE_OF_USER : 用户按下POWER键 , 当前是否处于锁屏界面,若是(mShowing)则重置显示界面,否则重新显示锁屏界面  
    38.     // 2、OFF_BECAUSE_OF_TIMEOUT : 屏幕超时,常见情况就是一段时间没有操作屏幕,手机处于灰暗状态。          处理行为:     
    39.     //     发送Action值为DELAYED_KEYGUARD_ACTION的广播,因为该类注册了该Intent广播,接受到时会调用doKeyguard()方法锁屏  
    40.     // 3、OFF_BECAUSE_OF_PROX_SENSOR:接打电话时,距离感应太近导致暗屏,此时由于PowerManager那儿已经处理了暗屏,不需要做任何事  
    41.     // 最后,如果以上逻辑都不成立,调用 doKeyguard()方法显示屏幕                         
    42.     public void onScreenTurnedOff(int why) {  
    43.        ...  
    44.     }  
    45.     /** 
    46.      * Let's us know the screen was turned on. 
    47.      */  
    48.     public void onScreenTurnedOn() {  
    49.         synchronized (this) {  
    50.             ...  
    51.             notifyScreenOnLocked();  //通知亮屏  
    52.         }  
    53.     }  
    54.     /** Enable the keyguard if the settings are appropriate. */  
    55.     private void doKeyguard() {  
    56.         synchronized (this) {  
    57.             ...  
    58.             showLocked();//显示锁屏界面  
    59.         }  
    60.     }  
    61.     //该方法的调用时机就是当按下POWER键时,系统会回调该方法 keyCode值一般为 26  
    62.     public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) {  
    63.         //操作按键是否能唤醒屏幕   
    64.         if (isWakeKeyWhenKeyguardShowing(keyCode)) {  
    65.             // give the keyguard view manager a chance to adjust the state of the  
    66.             // keyguard based on the key that woke the device before poking  
    67.             // the wake lock  
    68.             wakeWhenReadyLocked(keyCode);//开始唤醒屏幕咯  
    69.             return true;  
    70.         } else {  
    71.             return false;  
    72.         }  
    73.     }  
    74.     /** {@inheritDoc} */  //在一定时间内保存屏幕为亮屏状态  
    75.     public void pokeWakelock(int holdMs) {  
    76.         ...  
    77.     }  
    78.     //表示成功得分完成了解锁操作  
    79.     public void keyguardDone(boolean authenticated, boolean wakeup) {  
    80.         synchronized (this) {  
    81.             //发送给Handler 进行异步处理  
    82.             Message msg = mHandler.obtainMessage(KEYGUARD_DONE);  
    83.             msg.arg1 = wakeup ? 1 : 0;  
    84.             mHandler.sendMessage(msg);  
    85.             if (authenticated) {  
    86.                 mUpdateMonitor.clearFailedAttempts(); //清除错误登录次数  
    87.             }  
    88.             ...  
    89.         }  
    90.     }  
    91.     //Handler对象 , 异步处理  
    92.     private Handler mHandler = new Handler() {  
    93.         @Override  
    94.         public void handleMessage(Message msg) {  
    95.             switch (msg.what) {  
    96.               ...  //异步处理  
    97.             }  
    98.         }  
    99.     };  
    100.     //异步处理完成开锁成功  
    101.     private void handleKeyguardDone(boolean wakeup) {   
    102.         handleHide(); //释放该Keyguard对应的窗口  
    103.         mWakeLock.release();  
    104.         mContext.sendBroadcast(mUserPresentIntent); //解锁成功,发送Intent信息  
    105.     }  
    106.     //显示锁屏界面  
    107.     private void handleShow() {  
    108.         synchronized (KeyguardViewMediator.this) {  
    109.             ...  
    110.             mKeyguardViewManager.show();  
    111.             mShowing = true;  
    112.             ...  
    113.         }  
    114.     }  
    115.     private void handleHide() {  
    116.         synchronized (KeyguardViewMediator.this) {  
    117.             //去除锁屏界面对应的窗口  
    118.             mKeyguardViewManager.hide();  
    119.             mShowing = false;  
    120.            ...  
    121.         }  
    122.     }  
    123.     //设置状态栏enable状态 , 例如:能否被下拉等  
    124.     private void adjustStatusBarLocked() {  
    125.             ...  
    126.             // if the keyguard is shown, allow the status bar to open  
    127.             // only if the keyguard is insecure and is covered by another window  
    128.             boolean enable = !mShowing || (mHidden && !isSecure());  
    129.             mStatusBarManager.disable(enable ?StatusBarManager.DISABLE_NONE : StatusBarManager.DISABLE_EXPAND);  
    130.         }  
    131.     }  
    132. }  
    public class KeyguardViewMediator implements KeyguardViewCallback, KeyguardUpdateMonitor.SimStateCallback {
        private boolean mSystemReady;  //启动成功 由SystemServer调用
    
        /**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 window
        private boolean mHidden = false; //被其他窗口掩盖 , 例如来电时锁屏被掩盖
        private boolean mScreenOn = false; // 是否亮屏
    
        public KeyguardViewMediator(Context context, PhoneWindowManager callback,
                LocalPowerManager powerManager) {
            ...
            //构造相关实例对象
            mKeyguardViewProperties = new LockPatternKeyguardViewProperties(
                    new LockPatternUtils(mContext), mUpdateMonitor);
    
            mKeyguardViewManager = new KeyguardViewManager(
                    context, WindowManagerImpl.getDefault(), this,
                    mKeyguardViewProperties, mUpdateMonitor);
            //解锁成功后发送的Intent
            mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT);
            mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        }
        /** Called to let us know the screen was turned off.
         *   @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
         *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
         *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
         */
        //屏幕变灰暗  , 原因有如下:以及对应的逻辑处理。
        // 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值一般为 26
        public 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 lock
                wakeWhenReadyLocked(keyCode);//开始唤醒屏幕咯
                return true;
            } else {
                return false;
            }
        }
        /** {@inheritDoc} */  //在一定时间内保存屏幕为亮屏状态
        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() {
            @Override
            public 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 window
                boolean enable = !mShowing || (mHidden && !isSecure());
                mStatusBarManager.disable(enable ?StatusBarManager.DISABLE_NONE : StatusBarManager.DISABLE_EXPAND);
            }
        }
    }

     

     

         该类的很多方法都是由PhoneWindowManager调用访问的。

             基本上把一些重要的类及其相关的方法给走了一遍吧,对看源码的还是很有帮助的。因为我的理解还不是很深入,可能有偏颇的

      地方。希望以后能够组件完善起来。 阿门 !

     

      

      问题:如何在框架中, 解除锁屏 ?

     

           引入:该问题是在CSDN论坛上回答一位网友引发的,最开始由于我也只是简单看了下,因此也就事论事回答了一个小问题。

      随着看的越来越深入,慢慢的也在心里长生了涟漪。经过尝试、烧鸡验证,发现如下办法行的通,而且效果还比较好。风险应该

      比较小吧。 希望正在在框架修改的同学,慎重行事。

     

           基本思路:毫无疑问,我的想法就是每次需要显示Keyguard---锁屏界面时,我们并不真正的去锁屏,而只是提供了一个空的

      方法去给系统调用,让系统觉得我们“锁屏”了,同样也不去真正的隐藏“锁屏”界面,提供一个空壳给系统调用。由于可能涉及

      到其它问题,例如:能否下拉状态栏,按下POWER键后,屏幕很快休眠等。Come on ,我们需要统一做处理。

     

        所有步骤函数都发生在KeyguardViewMediator 类中,注释部分为我们所添加的。

     

          Step 1、  取消  真正的去锁屏实现

     

    1. //该方法会显示锁屏界面,我们使其成为一个空壳子  
    2. private void handleShow() {  
    3.     synchronized (KeyguardViewMediator.this) {  
    4.         if (DEBUG) Log.d(TAG, "handleShow");  
    5.         if (!mSystemReady) return;  
    6.   
    7.         playSounds(true);  
    8.         //Begin : Modifid by qinjuning       
    9.           
    10.         //mKeyguardViewManager.show();  //     
    11.         //mShowing = true;              //  
    12.         //adjustUserActivityLocked();   //  
    13.         //adjustStatusBarLocked();     //取消对状态栏的控制  
    14.           
    15.         //End  
    16.         try {  
    17.             ActivityManagerNative.getDefault().closeSystemDialogs("lock");  
    18.         } catch (RemoteException e) {  
    19.         }  
    20.         mShowKeyguardWakeLock.release();  
    21.     }  
    22. }  
    //该方法会显示锁屏界面,我们使其成为一个空壳子
    private void handleShow() {
        synchronized (KeyguardViewMediator.this) {
            if (DEBUG) Log.d(TAG, "handleShow");
            if (!mSystemReady) return;
    
            playSounds(true);
            //Begin : Modifid by qinjuning     
            
            //mKeyguardViewManager.show();  //   
            //mShowing = true;              //
            //adjustUserActivityLocked();   //
            //adjustStatusBarLocked();     //取消对状态栏的控制
            
            //End
            try {
                ActivityManagerNative.getDefault().closeSystemDialogs("lock");
            } catch (RemoteException e) {
            }
            mShowKeyguardWakeLock.release();
        }
    }

     

          Step 2、  取消  真正的去隐藏锁屏实现       

     

    1. //真正的隐藏屏幕实现  
    2. private void handleHide() {  
    3.     synchronized (KeyguardViewMediator.this) {  
    4.         if (DEBUG) Log.d(TAG, "handleHide");  
    5.         if (mWakeAndHandOff.isHeld()) {  
    6.             Log.w(TAG, "attempt to hide the keyguard while waking, ignored");  
    7.             return;  
    8.         }  
    9.         // only play "unlock" noises if not on a call (since the incall UI  
    10.         // disables the keyguard)  
    11.         if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {  
    12.             playSounds(false);  
    13.         }  
    14.         //Begin : Modifid by qinjuning    
    15.           
    16.         //mKeyguardViewManager.hide();  
    17.         //mShowing = false;   
    18.         //adjustUserActivityLocked();         
    19.         //adjustStatusBarLocked();         //取消对状态栏的控制  
    20.           
    21.         //End  
    22.     }  
    23. }  
    //真正的隐藏屏幕实现
    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

     

    1. private void handleWakeWhenReady(int keyCode) {  
    2.     synchronized (KeyguardViewMediator.this) {  
    3.         if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")");  
    4.   
    5.         // this should result in a call to 'poke wakelock' which will set a timeout  
    6.         // on releasing the wakelock  
    7.         if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) {  
    8.             // poke wakelock ourselves if keyguard is no longer active  
    9.             Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves");  
    10.             //Begin : Modifid by qinjuning    
    11.             //pokeWakelock();  //按下POWER键时, 解除屏幕由亮变暗的Bug     
    12.             //End  
    13.         }  
    14.         /** 
    15.          * Now that the keyguard is ready and has poked the wake lock, we can 
    16.          * release the handoff wakelock 
    17.          */  
    18.         mWakeAndHandOff.release();  
    19.   
    20.         if (!mWakeLock.isHeld()) {  
    21.             Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq");  
    22.         }  
    23.     }  
    24. }  
    private void handleWakeWhenReady(int keyCode) {
        synchronized (KeyguardViewMediator.this) {
            if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")");
    
            // this should result in a call to 'poke wakelock' which will set a timeout
            // on releasing the wakelock
            if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) {
                // poke wakelock ourselves if keyguard is no longer active
                Log.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();
    
            if (!mWakeLock.isHeld()) {
                Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq");
            }
        }
    }

      

           经过真机测试是通过的,但其他风险并不清楚。 这个方法只是提供了一个学习的途径吧。大家慎重行事。

     

        上面Step 1、以及Step 2可以由如下方法代替:

               将属性mExternallyEnabled 设置为 false, 接下来需要显示界面时都不会继续走下去,如下函数:

     

    1. /** 
    2.  * Enable the keyguard if the settings are appropriate. 
    3.  */  //显示界面  
    4. private void doKeyguard() {  
    5.     synchronized (this) {  
    6.         // if another app is disabling us, don't show  
    7.         if (!mExternallyEnabled) {   //mExternallyEnabled 为false   
    8.             if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");  
    9.   
    10.             // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes  
    11.             // for an occasional ugly flicker in this situation:  
    12.             // 1) receive a call with the screen on (no keyguard) or make a call  
    13.             // 2) screen times out  
    14.             // 3) user hits key to turn screen back on  
    15.             // instead, we reenable the keyguard when we know the screen is off and the call  
    16.             // ends (see the broadcast receiver below)  
    17.             // TODO: clean this up when we have better support at the window manager level  
    18.             // for apps that wish to be on top of the keyguard  
    19.             return;  
    20.         }  
    21.         ...  
    22.     }  
    23. }  
    /**
     * Enable the keyguard if the settings are appropriate.
     */  //显示界面
    private void doKeyguard() {
        synchronized (this) {
            // if another app is disabling us, don't show
            if (!mExternallyEnabled) {   //mExternallyEnabled 为false 
                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
    
                // 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 keyguard
                return;
            }
            ...
        }
    }

     

     

     

          该方法的一个缺点就是,假如存在重新调用了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类中

     

    1. /** 
    2.  * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide 
    3.  * a way for external stuff to override normal keyguard behavior.  For instance 
    4.  * the phone app disables the keyguard when it receives incoming calls. 
    5.  */   
    6. public void setKeyguardEnabled(boolean enabled) {  
    7.     synchronized (this) {  
    8.         mExternallyEnabled = enabled;  //保存值,该值会在doKeyguard()时用到,如果为false ,则不进行锁屏  
    9.   
    10.         if (!enabled && mShowing) {  
    11.             if (mExitSecureCallback != null) {//该判断为false  
    12.                 ...   
    13.                 return ;  
    14.             }  
    15.             mNeedToReshowWhenReenabled = true;  //置为真,以便下次调用  
    16.             hideLocked(); //已经显示了锁屏界面,则取消隐藏界面  
    17.         } else if (enabled && mNeedToReshowWhenReenabled) { //重新显示锁屏界面  
    18.             mNeedToReshowWhenReenabled = false;  
    19.   
    20.             if (mExitSecureCallback != null) {//该判断为false  
    21.                 
    22.             } else {  
    23.                 showLocked(); //显示隐藏界面  
    24.                 ...  
    25.             }  
    26.         }  
    27.     }  
    28. }  
    /**
     * Same semantics as {@link 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 ,则不进行锁屏
    
            if (!enabled && mShowing) {
                if (mExitSecureCallback != null) {//该判断为false
                    ... 
                    return ;
                }
                mNeedToReshowWhenReenabled = true;  //置为真,以便下次调用
                hideLocked(); //已经显示了锁屏界面,则取消隐藏界面
            } else if (enabled && mNeedToReshowWhenReenabled) { //重新显示锁屏界面
                mNeedToReshowWhenReenabled = false;
    
                if (mExitSecureCallback != null) {//该判断为false
                  
                } else {
                    showLocked(); //显示隐藏界面
                    ...
                }
            }
        }
    }

     

           使用这两个方法时,记得加上如下权限android.permission.DISABLE_KEYGUARD

       为了在亮屏时,达到取消显示界面的效果,我们还需要知道 一下两个广播:

     

             屏幕变暗以及屏幕点亮的广播

     

                        android.intent.action.SCREEN_ON  --- 屏幕变亮

                        android.intent.action.SCREEN_OFF ---- 屏幕点暗

     

             关于这两个广播的说明请参考如下博客:http://www.2cto.com/kf/201111/109815.html

        

      于是在监听到屏幕变暗/变亮时,通过KeyguardManager 类实现即可。对与用户而言,就相当于解除了锁屏界面了。

       可能代码如下:

     

    1. //屏幕变暗/变亮的广播 , 我们要调用KeyguardManager类相应方法去解除屏幕锁定  
    2. private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver(){  
    3.     @Override  
    4.     public void onReceive(Context context , Intent intent) {  
    5.         String action = intent.getAction() ;  
    6.           
    7.         Log.i(TAG, intent.toString());  
    8.           
    9.         if(action.equals("android.intent.action.SCREEN_OFF")  
    10.                 || action.equals("android.intent.action.SCREEN_ON") ){  
    11.             mKeyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);  
    12.             mKeyguardLock = mKeyguardManager.newKeyguardLock("zdLock 1");   
    13.             mKeyguardLock.disableKeyguard();  
    14.             startActivity(zdLockIntent);  
    15.         }  
    16.     }  
    17.       
    18. };  
    	//屏幕变暗/变亮的广播 , 我们要调用KeyguardManager类相应方法去解除屏幕锁定
    	private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver(){
    		@Override
    		public 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);
    			}
    		}
    		
    	};

     

           关于参考/设计一个好的解锁界面以及仿正点闹钟滑动解锁,请看我的这篇博客:

           《 Android自定义锁屏实现----仿正点闹钟滑屏解锁

     

            PS:如果觉得本文对你有帮助,请给顶一下。

        

     

           最后,可能有些同学在做App时,可能想获取系统的登录次数等,例如:登录失败次数等 ; Android系统已经 为我们提供好

       了框架去处理,具体对应类是DevicePolicyManager类,关于该类的具体使用请参见该博客:

                     《【Android设备管理】 利用DevicePolicyManager执行屏幕锁定 》 。

     

  • 相关阅读:
    linux安装JRE和Tomcat
    微信公众号授权登录
    linux Nginx设置多级域名
    bootstrap制作收藏夹导航
    js下拉菜单
    QQ授权登录
    centos7.6下安装LNMP环境(linux+nginx+mysql5.7+PHP)
    typora快捷键(转载)
    旋转魔方(2)-添加照片
    test
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/3650976.html
Copyright © 2020-2023  润新知