Android9.0 SystemUI代码走读__锁屏模块_01

这篇文章会采用代码走读的方式,结合简单的流程图,和大家一起看下Android9.0 上的锁屏模块相关代码,其它android版本应该也差不多,不过这篇文件的讲解是基于android9.0上的代码。

在了解某个模块的之前,我们经常是有疑问才去了解,在这之前,我也是有下面几个疑问:

1)锁屏界面代码是包含在哪个模块的;

2)亮屏、灭屏操作,锁屏界面显示流程是怎样的;

3)锁屏界面上滑,显示登陆密码界面流程是怎样的;

4)按power键开机的时候,为啥没有显示锁屏界面;

5)我想修改锁屏界面内容,应该关注哪些类和布局可以快速修改;

6)  遇到的一些问题以及分析解决;

有疑问总是好事,这篇文章会针对上面的疑问来一步步展开讲解;

写在前面

在Android系统上,短按电源power键,会进入灭屏和亮屏。如果我们在设置中设置了屏幕锁定方式有密码的话,亮屏的时候,我们会看到如下图所示的锁屏界面,然后锁屏界面上滑,就是密码验证界面,输入正确密码后,才能进入系统界面。

​ image

一、锁屏界面代码是包含在哪个模块的

答:是在SystemUI模块。

二、锁屏界面显示流程是怎样的

锁屏界面的处理是在SystemUI中进行处理。下图是系统开机后,涉及到锁屏相关逻辑的简单流程图,我们先来有个大概的了解,起码知道涉及到哪些重要的类。

KeyguardViewMediator.java

StatusBarKeyguardViewManager.java

StatusBarWindowManager.java

StatusBar.java

KeyguardBouncer.java

KeyguardHostView.java

KeyguardSecurityContainer.java

流程图-01

面我们已经看到有一个很重要的类KeyguardViewMediator.java ,是的,我们首先就看下这个类的代码。

看代码之前,我们先看下这个类的最前面的注释吧,我们翻译下重要的来看下,方便整体的理解(本人英语水平有限,大伙可以直接看英文理解理解)。

/**
 * Mediates requests related to the keyguard.  This includes queries about the
 * state of the keyguard, power management events that effect whether the keyguard
 * should be shown or reset, callbacks to the phone window manager to notify
 * it of when the keyguard is showing, and events from the keyguard view itself
 * stating that the keyguard was succesfully unlocked.
 *  
 *    //Mediates(调解) 主要处理和锁屏相关的请求。这些内容包括查询锁屏的状态、根据Power 管理事 
 *    件决定锁屏是否显示或者重置、采用回调将当前是否是锁屏状态回调给phone window manager,以及 
 *    锁屏是否成功解锁这种来自锁屏自身的view的事件。
 *     
 *
 * Note that the keyguard view is shown when the screen is off (as appropriate)
 * so that once the screen comes on, it will be ready immediately.
 *   
 *   //注意了:锁屏界面是在灭屏的时候就显示处理了(视情况而定),这样方便屏幕一亮的时候,锁屏界面
 *     能快速的显示出来。
 *
 * Example external events that translate to keyguard view changes:
 * - screen turned off -> reset the keyguard, and show it so it will be ready
 *   next time the screen turns on
 * - keyboard is slid open -> if the keyguard is not secure, hide it
 *  
 *  //外部事件引起锁屏界面变化的例子:
 *    灭屏->锁屏重置,然后显示,这样下次亮屏的时候,锁屏是准备好的。
 *
 * Events from the keyguard view:
 * - user succesfully unlocked keyguard -> hide keyguard view, and no longer
 *   restrict input events.
 *   
 *   //锁屏试图的事件传递:
 *    用户成功解锁锁屏->隐藏锁屏视图,不再限制输入事件
 *
 * Note: in addition to normal power managment events that effect the state of
 * whether the keyguard should be showing, external apps and services may request
 * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}.  When
 * false, this will override all other conditions for turning on the keyguard.
 *  
 *  //注意:外部apps或者服务可能会使用setKeyguardEnabled(boolean)接口来设置是否需要显示锁屏,
 *    为了使来自power management的关于锁屏是否应该显示的事件调用标准化,当setKeyguardEnabled设 
 *    的值为false的时候,这个会是推翻其它打开锁屏的条件
 /

我们根据上面注释的描述,来走读下按键灭屏、亮屏这个流程:
     screen turned off -> reset the keyguard, and show it so it will be ready next time the screen turns on

KeyguardViewMediator.java
----------------------------

 /**
   * 亮屏
   **/
  public void onScreenTurnedOn() {
        Trace.beginSection("KeyguardViewMediator#onScreenTurnedOn");
        notifyScreenTurnedOn();
        mUpdateMonitor.dispatchScreenTurnedOn();
        Trace.endSection();
  }

  /**
   * 灭屏
   **/
  public void onScreenTurnedOff() {
        notifyScreenTurnedOff();
        mUpdateMonitor.dispatchScreenTurnedOff();
  }

  ...

  private void handleNotifyScreenTurnedOff() {
        synchronized (this) {
            if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
            mStatusBarKeyguardViewManager.onScreenTurnedOff();
            mDrawnCallback = null;
        }
  }

三、 长按power键开机后,为啥不会显示锁屏界面

没有显示,那就是Android本来就这样设计的呗,哈哈,做开发的,很喜欢的一句话应该是“设计就是这样的啊”,然后摊摊手,表示无能为力。是不是设计就是如此,我们来看代码确认下吧。

我们来看下 KeyguardViewMediator.java中的具体实现:

1)系统起来的时候,会走onSystemReady()方法,然后通话发送handler信息进行处理,真正的处理就是在handleSystemReady()里面;

2)handleSystemReady()里面,我们重点看下doKeyguardLocked()方法,doKeyguradLocked()里面会有一些条件判断,条件不符合,则直接return掉;条件符合,才会走showLocked(options)方法进行锁屏界面的显示;

    /**
     * 系统起来会调用该方法通知系统起来了
     * 通过handler发送SYSTEM_READY信息进行一些事情的处理
     */
    public void onSystemReady() {
        Log.v(TAG,"--- onSystemReady();");
        mHandler.obtainMessage(SYSTEM_READY).sendToTarget();
    }

     private Handler mHandler = new Handler(Looper.myLooper(), null, true) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                  ......
                case SYSTEM_READY:
                    handleSystemReady();
                    break;
                  ......
            }
        }
    };

    private void handleSystemReady() {
        synchronized (this) {
            if (DEBUG) Log.d(TAG, "onSystemReady");
            mSystemReady = true;
            doKeyguardLocked(null);
            mUpdateMonitor.registerCallback(mUpdateCallback);
        }
        // Most services aren't available until the system reaches the ready state, so we
        // send it here when the device first boots.
        maybeSendUserPresentBroadcast();
    }

3)doKeyguardLocked()里面有个mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) 的判断,我们把这个的值打印下,会发现开机的时候,打印的值是false,lockedOrMissing和forceShow值默认为false,所以会直接return回去,没有继续走下面的流程了。

  1. 那我们现在知道了,是判断到lockScreen锁屏还没准备好,所以没有走显示锁屏的流程了。(这里具体没准备好的原因和判断条件,我还没有继续跟踪,我试过这里强制显示也是没有问题的,本来就是有个强制显示的参数forceShow,那说明这时需要强制显示也是可以的)
    private void doKeyguardLocked(Bundle options) {
             ......

            //------ 分析1  
            if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) && !lockedOrMissing && !forceShow) {
                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
                return;
            }

            ......
        }

        if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
        showLocked(options);
    }

五、我想修改锁屏界面内容,应该关注哪些类和布局可以快速修改

1)登陆密码验证界面

i、这里涉及到2个重要的类 KeyguardAbsKeyInputView.java和 KeyguardPasswordView.java ,密码的授权验证在KeyguardAbsKeyInputView.java类中处理,界面的显示是在KeyguardPasswordView.java 中进行处理。 我们看下下图贴的代码 KeyguardPasswordView.java 里面的onEditorAction()里面的处理,有个verifyPasswordAndUnlock()的方法,就是跳转到KeyguardAbsKeyInputView.java中进行密码的验证了。

如果我们希望修改密码验证的逻辑的话,就可以修改KeyguardAbsKeyInputView.java中的verifyPasswordAndUnlock()里面的内容。

ii、密码验证对应的布局文件keyguard_password_view.xml,如果我们希望在布局上添加内容,就可以在这个布局文件上添加了。

--------KeyguardPasswordView.java --------

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        // Check if this was the result of hitting the enter key
        final boolean isSoftImeEvent = event == null
                && (actionId == EditorInfo.IME_NULL
                || actionId == EditorInfo.IME_ACTION_DONE
                || actionId == EditorInfo.IME_ACTION_NEXT);
        final boolean isKeyboardEnterKey = event != null
                && KeyEvent.isConfirmKey(event.getKeyCode())
                && event.getAction() == KeyEvent.ACTION_DOWN;
        if (isSoftImeEvent || isKeyboardEnterKey) {
            verifyPasswordAndUnlock();
            return true;
        }
        return false;
    }

六、遇到的问题以及分析解决

i、点击密码登录输入框,有时没有正常腾出输入法

这个问题发现和在KeyguardViewMediator.java 中调用mStatusBarKeyguardViewManager.setNeedsInput(needsInput); 有关系。需要正常腾出输入法,首先需要确保setNeedInput设置的值为true。我后面的修改是,在KeyguardViewMediator.java中,onSystemReady()方法中,根据自己需要,重新去设置了下setNeedInput的值。

还有个地方得修改下,KeyguardPasswordView.java中,resetState()里面,如下图所示,屏蔽掉了些代码。屏蔽掉的代码是自动调用输入法的,每次进入密码登录界面,会走resetState()的流程,不过很奇怪,主动去调用一次,反而是没有正常调用出来。

    @Override
    protected void resetState() {
        mSecurityMessageDisplay.setMessage("");
        final boolean wasDisabled = mUserNameEntry.isEnabled();
        setPasswordEntryEnabled(true);
        setPasswordEntryInputEnabled(true);

        setUserNameEntryEnabled(true);
        setUserNameEntryInputEnabled(true);

       //屏蔽掉的代码
//        if (wasDisabled) {
//            mImm.showSoftInput(mUserNameEntry, InputMethodManager.SHOW_IMPLICIT);
//        }
    }

=======================================================================

*本人从事Android Camera相关开发已有5年,
*目前在深圳上班,
*小伙伴记得点我头像关注,也可以关注我的微信公众号【小驰笔记】,希望和更多的小伙伴一起交流 ~

posted @ 2021-01-13 18:02  小驰行动派  阅读(731)  评论(0编辑  收藏  举报