本文简单分析,android启动之后,锁屏界面启动过程。
android系统开机后会运行PhoneWindowManage管理系统相关按键和事件,
看下PhoneWindowManager锁屏相关
1.Pwm初始化KeyguardViewMediator类,用来接受PhoneWindowManager传递相关事件
2.系统启动完成会调用SystemReady函数,进入锁屏流程
/** {@inheritDoc} */ 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(); } }); } }
* Let us know that the system is ready after startup. */ public void onSystemReady() { synchronized (this) { if (DBG_WAKE) Log.d(TAG, "onSystemReady"); mSystemReady = true; doKeyguardLocked(); } }
/** * Send message to keyguard telling it to show itself * @see #handleShow() */ private void showLocked() { if (DEBUG) Xlog.d(TAG, "showLocked"); // ensure we stay awake until we are finished displaying the keyguard mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW); if (isAlarmBoot() && !mChecked) { mChecked = true; Log.i(TAG, "it's alarm boot, delay 3s to show"); mHandler.sendMessageDelayed(msg, 5000); } else { mHandler.sendMessage(msg); } }
/** * Handle message sent by {@link #showLocked}. * @see #SHOW */ private void handleShow() { synchronized (KeyguardViewMediator.this) { if (DEBUG) Xlog.d(TAG, "handleShow"); if (!mSystemReady) return; if (mShowing == true) return; mShowCount++; //avoid the int overflow if (mShowCount == (int)Math.pow(2, 32)){ mShowCount=2; } Xlog.d(TAG, "handleShow, count="+mShowCount); mKeyguardViewManager.show(); mShowing = true; adjustUserActivityLocked(); adjustStatusBarLocked(); try { ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { } // Do this at the end to not slow down display of the keyguard. playSounds(true); mShowKeyguardWakeLock.release(); } }
/** * Show the keyguard. Will handle creating and attaching to the view manager * lazily. */ public synchronized void show() { if (DEBUG) Xlog.d(TAG, "show(); mKeyguardView==" + mKeyguardView); Resources res = mContext.getResources(); boolean enableScreenRotation = SystemProperties.getBoolean("lockscreen.rot_override",false) || res.getBoolean(R.bool.config_enableLockScreenRotation); if (mKeyguardHost == null) { if (DEBUG) Xlog.d(TAG, "keyguard host is null, creating it..."); mKeyguardHost = new KeyguardViewHost(mContext, mCallback); final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER | WindowManager.LayoutParams. FLAG_KEEP_SURFACE_WHILE_ANIMATING | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; if (mUpdateMonitor.DM_IsLocked()) {//in the first created flags &= ~WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; flags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; } else { flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; flags |= WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; } if (!mNeedsInput) { flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } if (ActivityManager.isHighEndGfx(((WindowManager)mContext. getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay())) { flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } WindowManager.LayoutParams lp = new WindowManager.LayoutParams( stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD, flags, PixelFormat.TRANSLUCENT); lp.softInputMode = WindowManager.LayoutParams. SOFT_INPUT_ADJUST_RESIZE; lp.windowAnimations = com.android.internal.R.style. Animation_LockScreen; if (ActivityManager.isHighEndGfx(((WindowManager)mContext. getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay())) { lp.flags |= WindowManager.LayoutParams. FLAG_HARDWARE_ACCELERATED; lp.privateFlags |= WindowManager.LayoutParams. PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; } lp.setTitle("Keyguard"); mWindowLayoutParams = lp; mViewManager.addView(mKeyguardHost, lp); } if (enableScreenRotation || FeatureOption.MTK_TB_APP_LANDSCAPE_SUPPORT ) { if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!"); mWindowLayoutParams.screenOrientation = ActivityInfo. SCREEN_ORIENTATION_SENSOR; } else { if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!"); mWindowLayoutParams.screenOrientation = ActivityInfo. SCREEN_ORIENTATION_NOSENSOR; } mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); if (mKeyguardView == null) { if (DEBUG) Xlog.d(TAG, "keyguard view is null, creating it..."); mKeyguardView = mKeyguardViewProperties.createKeyguardView( mContext, mUpdateMonitor, this); mKeyguardView.setId(R.id.lock_screen); mKeyguardView.setCallback(mCallback); final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mKeyguardHost.addView(mKeyguardView, lp); if (mScreenOn) { mKeyguardView.show(); } } // Disable aspects of the system/status/navigation bars that are not appropriate or // useful for the lockscreen but can be re-shown by dialogs or SHOW_WHEN_LOCKED activities. // Other disabled bits are handled by the KeyguardViewMediator talking directly to the // status bar service. int visFlags = ( View.STATUS_BAR_DISABLE_BACK | View.STATUS_BAR_DISABLE_HOME); mKeyguardHost.setSystemUiVisibility(visFlags); mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); mKeyguardHost.setVisibility(View.VISIBLE); mKeyguardView.requestFocus(); }
mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);
看下mKeyguraViewProperties 通过源码可知KeyViewMediator初始化创建,传入
KeyguardViewManager mKeyguardViewProperties = new LockPatternKeyguardViewProperties(mLockPatternUtils, mUpdateMonitor);
mKeyguardViewManager = new KeyguardViewManager( context, WindowManagerImpl.getDefault(), this, mKeyguardViewProperties, mUpdateMonitor);
8.LockPatternKeyguardViewProperties类中CreateKeyGuardView函数,初始化 LockPatternKeyguardView,LockPatternKeyguardView便是我们的锁屏界面
/** * Knows how to create a lock pattern keyguard view, and answer questions about * it (even if it hasn't been created, per the interface specs). */ public class LockPatternKeyguardViewProperties implements KeyguardViewProperties { private final LockPatternUtils mLockPatternUtils; private final KeyguardUpdateMonitor mUpdateMonitor; /** * @param lockPatternUtils Used to know whether the pattern enabled, and passed * onto the keygaurd view when it is created. * @param updateMonitor Used to know whether the sim pin is enabled, and passed * onto the keyguard view when it is created. */ public LockPatternKeyguardViewProperties(LockPatternUtils lockPatternUtils, KeyguardUpdateMonitor updateMonitor) { mLockPatternUtils = lockPatternUtils; mUpdateMonitor = updateMonitor; } public KeyguardViewBase createKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor, KeyguardWindowController controller) { return new LockPatternKeyguardView(context, updateMonitor, mLockPatternUtils, controller); } public boolean isSecure() { return mLockPatternUtils.isSecure() || isSimPinSecure(); } private boolean isSimPinSecure() { final IccCard.State simState = mUpdateMonitor.getSimState(Phone. GEMINI_SIM_1); final IccCard.State sim2State = mUpdateMonitor.getSimState(Phone. GEMINI_SIM_2); return (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED || simState == IccCard.State.PERM_DISABLED || sim2State == IccCard.State.PIN_REQUIRED || sim2State == IccCard.State.PUK_REQUIRED || sim2State == IccCard.State.PERM_DISABLED || simState == IccCard.State.ABSENT && sim2State == IccCard.State.ABSENT); } } 9.看下LockPatternKeyguardView初始流程 /** * @param context Used to inflate, and create views. * @param updateMonitor Knows the state of the world, and passed along to each * screen so they can use the knowledge, and also register for callbacks * on dynamic information. * @param lockPatternUtils Used to look up state of lock pattern. */ public LockPatternKeyguardView( Context context, KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils, KeyguardWindowController controller) { super(context); mHandler = new Handler(this); mConfiguration = context.getResources().getConfiguration(); mEnableFallback = false; mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard. no_require_sim")); mUpdateMonitor = updateMonitor; mLockPatternUtils = lockPatternUtils; mWindowController = controller; mHasOverlay = false; mUpdateMonitor.registerDeviceInfoCallback(this); mUpdateMonitor.registerPhoneStateCallback(this); mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { mForgotPattern = false; if (mIsVerifyUnlockOnly) { // navigating away from unlock screen during verify mode means // we are done and the user failed to authenticate. mIsVerifyUnlockOnly = false; getCallback().keyguardDone(false); } else { updateScreen(Mode.LockScreen, false); } } public void goToUnlockScreen() { final IccCard.State simState = mUpdateMonitor.getSimState( Phone.GEMINI_SIM_1); final IccCard.State sim2State = mUpdateMonitor.getSimState( Phone.GEMINI_SIM_2); if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED && !mLockPatternUtils.isPukUnlockScreenEnable()) || (sim2State == IccCard.State.PUK_REQUIRED && !mLockPatternUtils.isPukUnlockScreenEnable())){ // stuck on lock screen when sim missing or // puk'd but puk unlock screen is disabled return; } if (!isSecure()) { getCallback().keyguardDone(true); } else { updateScreen(Mode.UnlockScreen, false); } } public void forgotPattern(boolean isForgotten) { if (mEnableFallback) { mForgotPattern = isForgotten; updateScreen(Mode.UnlockScreen, false); } } public boolean isSecure() { return LockPatternKeyguardView.this.isSecure(); } public boolean isVerifyUnlockOnly() { return mIsVerifyUnlockOnly; } public void recreateMe(Configuration config) { removeCallbacks(mRecreateRunnable); post(mRecreateRunnable); } public void takeEmergencyCallAction() { mHasOverlay = true; // Continue showing FaceLock area until dialer comes up or call is resumed if (mLockPatternUtils.usingBiometricWeak() && mLockPatternUtils.isBiometricWeakInstalled() && mFaceLockServiceRunning) { showFaceLockAreaWithTimeout( FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT); } // FaceLock must be stopped if it is running stopAndUnbindFromFaceLock(); pokeWakelock(EMERGENCY_CALL_TIMEOUT); if (TelephonyManager.getDefault().getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) { mLockPatternUtils.resumeCall(); } else { Intent intent = new Intent(ACTION_EMERGENCY_DIAL); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); getContext().startActivity(intent); } } public void pokeWakelock() { getCallback().pokeWakelock(); } public void pokeWakelock(int millis) { getCallback().pokeWakelock(millis); } public void keyguardDone(boolean authenticated) { getCallback().keyguardDone(authenticated); mSavedState = null; // clear state so we re-establish when locked again } public void keyguardDoneDrawing() { // irrelevant to keyguard screen, they shouldn't be calling this } public void reportFailedUnlockAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); if (DEBUG) Xlog.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts + " (enableFallback=" + mEnableFallback + ")"); final boolean usingPattern = mLockPatternUtils. getKeyguardStoredPasswordQuality() == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; final int failedAttemptsBeforeWipe = mLockPatternUtils. getDevicePolicyManager() .getMaximumFailedPasswordsForWipe(null); final int failedAttemptWarning = LockPatternUtils. FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT; final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ? (failedAttemptsBeforeWipe - failedAttempts) : Integer.MAX_VALUE; // because DPM returns 0 if no restriction if (remainingBeforeWipe < LockPatternUtils. FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) { // If we reach this code, it means the user has installed a DevicePolicyManager // that requests device wipe after N attempts. Once we get below the grace // period, we'll post this dialog every time as a clear warning until the // bombshell hits and the device is wiped. if (remainingBeforeWipe > 0) { showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe); } else { // Too many attempts. The device will be wiped shortly. Slog.i(TAG, "Too many unlock attempts; device will be wiped!"); showWipeDialog(failedAttempts); } } else { boolean showTimeout = (failedAttempts % LockPatternUtils. FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0; if (usingPattern && mEnableFallback) { if (failedAttempts == failedAttemptWarning) { showAlmostAtAccountLoginDialog(); showTimeout = false; // don't show both dialogs } else if (failedAttempts >= LockPatternUtils. FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode, false); // don't show timeout dialog because we show account unlock screen next showTimeout = false; } } if (showTimeout) { showTimeoutDialog(); } } mLockPatternUtils.reportFailedPasswordAttempt(); } public boolean doesFallbackUnlockScreenExist() { return mEnableFallback; } public void reportSuccessfulUnlockAttempt() { mFailedFaceUnlockAttempts = 0; mLockPatternUtils.reportSuccessfulPasswordAttempt(); } }; /** * We'll get key events the current screen doesn't use. see * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)} */ setFocusableInTouchMode(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); updateScreen(getInitialMode(), false); maybeEnableFallback(context); }
private void updateScreen(Mode mode, boolean force) { Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode + " last mode=" + mMode + ", force = " + force); mMode = mode; // Re-create the lock screen if necessary if (mode == Mode.LockScreen || mShowLockBeforeUnlock) { if (force || mLockScreen == null) { recreateLockScreen(); } } // 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) { final UnlockMode unlockMode = getUnlockMode(); if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { recreateUnlockScreen(unlockMode); } } // visibleScreen should never be null 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) { Xlog.v(TAG, "Gone=" + goneScreen); Xlog.v(TAG, "Visible=" + visibleScreen); } if (mScreenOn) { if (goneScreen != null && goneScreen.getVisibility() == View. VISIBLE) { ((KeyguardScreen) goneScreen).onPause(); } if (visibleScreen.getVisibility() != View.VISIBLE) { ((KeyguardScreen) visibleScreen).onResume(); } } if (goneScreen != null) { 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()); } }
private void recreateLockScreen() { Log.i(TAG, "recreateLockScreen"); if (mLockScreen != null) { ((KeyguardScreen) mLockScreen).onPause(); ((KeyguardScreen) mLockScreen).cleanUp(); removeView(mLockScreen); } mLockScreen = createLockScreen(); mLockScreen.setVisibility(View.INVISIBLE); addView(mLockScreen); }