android 锁屏界面处理

锁屏相关的文件在android对应packagecom.android.internal.policy.impl

phoneWindowManager.java可以派发各种物理key,如PowerHomeVol+Vol-等等。那么,这个类是由谁启动的?

packagePolicy.java

public PhoneWindowManager makeNewWindowManager() {

        return new PhoneWindowManager();

}

这个方法实现创建这个类。而在PolicyManager.java下调用这个方法实现对PhoneWindowManager的创建。

但是,PhoneWindowManager.java中有一个init()方法,这个是这个类的初始化方法,它调用PowerManagerwindowManagerKeyguardViewMediator等等实现对PhoneWindowManager。这个Init()是在WindowManagerService.java下 的PolicyThread类下得Run方法中调用mPolicy.init(mContext, mService, mPM)

PhoneWindowManager.java这个类是非常重要的,这里注册了一个Orientation变化的监听类:

MyOrientationListener extends WindowOrientationListener,但是,它不能够自动进行更新,它的更新主要是依据接收广播进行的,此处大概就是JNI根据驱动获取相关Sensor消息然后发送消息。这里仅仅粗略说明在这个文件中有屏幕旋转的处理方法。

下面是锁屏的处理流程:

PhoneWindowManager.java中:

 public void systemReady() {

        // tell the keyguard

        mKeyguardMediator.onSystemReady();

        android.os.SystemProperties.set("dev.bootcomplete", "1"); 

        synchronized (mLock) {

            updateOrientationListenerLp();

            mSystemReady = true;

            mHandler.post(new Runnable() {

                public void run() {

                    updateSettings();

                }

            });

       }

 }

这个方法在开机时启动调用,然后mKeyguardMediator.onSystemReady()

在KeyGuardViewMeditor.java是一个非常重要的类,它用来响应电源键的处理(黑亮屏),查询解锁屏等等。

public void onSystemReady() {

        synchronized (this) {

            if (DEBUG) Log.d(TAG, "onSystemReady");

            mSystemReady = true; //系统准备好了

            doKeyguard(); //判断是否设定了锁

        }

}

private void doKeyguard()主要功能:Enable the keyguard if the settings are appropriate.意思就是如果在Setting里面设置了密码就激活keyguard。

1.如果设置了屏幕锁,黑屏后,在onScreenTurnedOff中doKeyguard()调用一次;

2.如果有SIM卡,且设置了PIN或PUK锁,那么调用doKeyguard();

3.TIMEROUT时调用doKeyguard();

4.接收到消息;DELAYED_KEYGUARD_ACTION或者TelephonyManager.ACTION_PHONE_STATE_CHANGED可能会调用

doKeyguard().

doKeyguard()方法最后调用了showLocked();

    private void showLocked() {

        if (DEBUG) Log.d(TAG, "showLocked");

        // ensure we stay awake until we are finished displaying the keyguard

        mShowKeyguardWakeLock.acquire();

        Message msg = mHandler.obtainMessage(SHOW);

        mHandler.sendMessage(msg);

    }

实际上就是发送消息显示SHOW

Handler接收到SHOW这个Message,进行相关处理:

进入KeyguardViewManager.java:

public synchronized void show()方法中:

if (mKeyguardView == null) {

  if (DEBUG) Log.d(TAG, "keyguard view is null, creating it...");

  mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);

  mKeyguardView.setId(R.id.lock_screen);

……

}

mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this)这个就是KeyguardViewBase创建一个KeyguardViewBase的对象,也就是管理LockUnlock画面的类实例

在Setting里面设置各种锁屏之后,在按power键重新开启时会产生lock或者unlock界面,需要输入密码或者绘出Pattern等操作后才能进入界面。这个锁定和解锁界面是由LockPatternKeyguardView这个类实现的。下面便是这个class的构造函数。

public LockPatternKeyguardView(

        Context context,

        KeyguardUpdateMonitor updateMonitor,

        LockPatternUtils lockPatternUtils,

        KeyguardWindowController controller)

重要实现:

mConfiguration = context.getResources().getConfiguration();

这个函数是用来获取系统的一些配置,在此用来决定是横屏还是竖屏。

mMode = getInitialMode();

这个则是获取系统的mode了。

mMode是这样的类型:

enum Mode {

        LockScreen,

        UnlockScreen

}

可以初步判断是lock还是unlock状态的flag枚举。获取这个状态是非常重要的,它决定初始化时究竟是显示unlock 界面还是lock界面。

private Mode getInitialMode() {

  boolean isPukRequired = false;

  for (int i = 0; i < TelephonyManager.getPhoneCount(); i++) {

        isPukRequired = isPukRequired || isSimPukLocked(i);

        if (isPukRequired) break;

}

 //这里是判断sim是否加入PUK锁或者sim卡不存在

 if (stuckOnLockScreenBecauseSimMissing() || isPukRequired) {

       return Mode.LockScreen;

 } else {

   // Show LockScreen first for any screen other than Pattern unlock.

  final boolean usingLockPattern = 

   mLockPatternUtils.getKeyguardStoredPasswordQuality()== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;

       if (isSecure() && usingLockPattern) {

              return Mode.UnlockScreen;

       } else {

              return Mode.LockScreen;

       }

}

}

对于isSecure这个函数,定义如下:

 private boolean isSecure() {

        UnlockMode unlockMode = getUnlockMode();

        boolean secure = false;

        switch (unlockMode) {

            case Pattern:

                secure = mLockPatternUtils.isLockPatternEnabled();

                break;

            case SimPin:

                for (int i = 0; i < TelephonyManager.getPhoneCount(); i++) {

                    // Check if subscription is PIN/PUK locked.

                    // isPinLocked returns true if the state is PIN_REQUIRED/PUK_REQUIRED.

                    secure = secure || getSimState(i).isPinLocked();

                    if (secure) break;

                }

                break;

            case Account:

                secure = true;

                break;

            case Password:

                secure = mLockPatternUtils.isLockPasswordEnabled();

                break;

            default:

                throw new IllegalStateException("unknown unlock mode " + unlockMode);

        }

        return secure;

很显然是判断,是否设置了解锁屏方式。是则返回true,否则false。

而usingLockPattern是判断是否是用pattern模式的。具体判断后面研究。

在获取相关初始状态后,就是一些回调函数的实现:

mKeyguardScreenCallback = new KeyguardScreenCallback(),这个是十分容易解决的。

在之后是:

// create both the lock and unlock screen so they are quickly available

    // when the screen turns on

mLockScreen = createLockScreen();

addView(mLockScreen);

final UnlockMode unlockMode = getUnlockMode();

if (DEBUG) Log.d(TAG,

   "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback="

            + mEnableFallback);

mUnlockScreen = createUnlockScreenFor(unlockMode);

mUnlockScreenMode = unlockMode;

maybeEnableFallback(context);

addView(mUnlockScreen);

updateScreen(mMode);

由注释可知:其实就是创建lock和unlock界面,这样切换时就可以直接显示而不必先创建在切换,造成时间的缓冲。那么究竟显示lock还是unlock界面就是最后那个调用。具体函数:

private void updateScreen(final Mode mode) {

  if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode

            + " last mode=" + mMode, new RuntimeException());

  mMode = mode;

  // Re-create the unlock screen if necessary. This is primarily required to properly handle

  // SIM state changes. This typically happens when this method is called by reset()

  if ((mode == Mode.UnlockScreen && mCurrentUnlockMode != getUnlockMode()) ||

                (getUnlockMode() == UnlockMode.SimPin)) {

      recreateUnlockScreen();

   }

   final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;

   final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;

   // do this before changing visibility so focus isn't requested before the input

   // flag is set

   mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());

   if (DEBUG_CONFIGURATION) {

        Log.v(TAG, "Gone=" + goneScreen);

        Log.v(TAG, "Visible=" + visibleScreen);

   }

   if (mScreenOn) {

        if (goneScreen.getVisibility() == View.VISIBLE) {

           ((KeyguardScreen) goneScreen).onPause();

   }

   if (visibleScreen.getVisibility() != View.VISIBLE) {

           ((KeyguardScreen) visibleScreen).onResume();

   }

        }

   goneScreen.setVisibility(View.GONE);

   visibleScreen.setVisibility(View.VISIBLE);

   requestLayout();

   if (!visibleScreen.requestFocus()) {

        throw new IllegalStateException("keyguard screen must be able to take "

                 + "focus when shown " + visibleScreen.getClass().getCanonicalName());

   }

}

这里mMode = mode;之后

 final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;

 final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;

很显然,这是根据mode决定显示lock还是unlock的。

关于在Unlock界面输入错误密码的提示流程:

当用户输入密码时,若不正确,此时就会报告错误:

在PasswordUnlockScreen.java中有一个函数verifyPasswordAndUnlock,如下:

private void verifyPasswordAndUnlock() {

        String entry = mPasswordEntry.getText().toString();

        if (mLockPatternUtils.checkPassword(entry)) {

            mCallback.keyguardDone(true);

            mCallback.reportSuccessfulUnlockAttempt();

        } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {

            mCallback.reportFailedUnlockAttempt();

//在这里,也就是输入次数是5的整数倍时,弹出报错对话框:

            if (0 == (mUpdateMonitor.getFailedAttempts()

                    % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {

                long deadline = mLockPatternUtils.setLockoutAttemptDeadline();

                handleAttemptLockout(deadline);

            }

        }

        mPasswordEntry.setText("");

    }

那么这个错误如何显示的?

上面代码有一处: mCallback.reportFailedUnlockAttempt()

reportFailedUnlockAttempt()函数是在LockPatternKeyguardView.java中,

  public void reportFailedUnlockAttempt() {

                mUpdateMonitor.reportFailedAttempt();

                final int failedAttempts = mUpdateMonitor.getFailedAttempts();

                final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()

                        == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;

                if (usingLockPattern && mEnableFallback && failedAttempts ==

                        (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET

                                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {

                    showAlmostAtAccountLoginDialog();

                } else if (usingLockPattern && mEnableFallback

                        && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {

                    mLockPatternUtils.setPermanentlyLocked(true);

                    updateScreen(mMode);

                } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)

                        == 0) {

                    showTimeoutDialog();

                }

                mLockPatternUtils.reportFailedPasswordAttempt();

            }

showAlmostAtAccountLoginDialog和showTimeoutDialog()决定显示什么样的Message:

private void showTimeoutDialog() {

//Get time to lock screen

        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;

//Announce a message 

String message = "";

//Get unlock mode

UnlockMode unlockMode = getUnlockMode();

if (unlockMode  == UnlockMode.password) {

         message = mContext.getString(

                 R.string.lockscreen_too_many_failed_attempts_dialog_message,

                 mUpdateMonitor.getFailedAttempts(),

                 timeoutInSeconds);

}

else {

          message = mContext.getString(

                 R.string.lockscreen_too_many_failed_attempts_dialog_message,

                 mUpdateMonitor.getFailedAttempts(),

                 timeoutInSeconds);

}

        final AlertDialog dialog = new AlertDialog.Builder(mContext)

                .setTitle(null)

                .setMessage(message)

                .setNeutralButton(R.string.ok, null)

                .create();

        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

        if (!mContext.getResources().getBoolean(

                com.android.internal.R.bool.config_sf_slowBlur)) {

            dialog.getWindow().setFlags(

                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND,

                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

        }

        dialog.show();

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值