Android4.4 screen lock Process
Shortly after graduation, the project needed to access the screen lock. from 2.2 to 4.1, it had fixed bugs and customized some features. It was not difficult to lock the screen before 4.1, but it took a lot of time. Because of its logic, views, and resources are distributed in different paths, it is like the beads scattered on the beach, it is quite difficult to think about it. At the beginning, the screen lock is to edit all fields to generate img. Later, the new skill get will perform a single compilation for the modified location. However, it is not convenient to compile the jar and import it to the mobile phone every time you restart it.
I never saw the lock screen again after I handed it over a year ago. The four Prince of Google rose to 4.4 a few days ago and found that the lock screen has changed a lot. I can slide pages and add and delete widgets, add and delete pages. It is simply a simplified version of launcher. I'm curious about how google changed, so I spent a lot of effort pulling google's latest source code. In android 4.4, the changes to this module are huge, and I will make a little bit of work here.
1. File directory:
A. The lock screen proxy is under Frameworks/base/policy/src/com/android/internal/policy/impl/keyguard:
B. The architecture and functions of the entire project are similar to those of systemUI in framework/package:
C. keyguard's external interface Frameworks/base/core/java/android/app/keyguardManager. java:
Before Android, some third-party lock screen software used this service interface to control the system lock screen (such as prohibiting the system lock screen). Now this interface is no longer recommended and has better practices:
/*** @ Deprecated use {@ link android. view. windowManager. layoutParams # FLAG_DISMISS_KEYGUARD} * and/or {@ link android. view. windowManager. layoutParams # FLAG_SHOW_WHEN_LOCKED} *. This method can be used to enable the application to disable the lock screen without additional permission application. This allows you to * Enables you to lock or unlock thekeyboard. get an instance of this class by * calling {@ link android. content. context # getSystemService (java. lang. string) Context. getSystemService ()}. * This class is wrapped by {@ link android. app. keyguardManagerKeyguardManager }. * @ param tag A tag that informallyidentifies who you are (for debugging who * is disabling he keyguard ). ** @ return A {@ link KeyguardLock} handle to use todisable and reenable the * keyguard. * // @ Deprecated public KeyguardLock newKeyguardLock (Stringtag) {return new KeyguardLock (tag );}
Keyguard lock screen Flowchart
Keyguard lock screen view hierarchy:
Key guard lock screen analysis:
1. PhoneWindowManager. java
This class is very powerful and important. It is derived from WindowManagerService and processes the top-level logic of phone, mainly including the following:
A) horizontal and vertical screen processing (screen rotation, etc)
publicvoidsetCurrentOrientationLw(intnewOrientation){synchronized (mLock){if (newOrientation != mCurrentAppOrientation) {mCurrentAppOrientation = newOrientation;updateOrientationListenerLp(); } } }
B) whether the status bar or navigation_bar is displayed.
privateintupdateSystemUiVisibilityLw() {// If there is no window focused,there will be nobody to handle the events// anyway, so just hang on inwhatever state we're in until things settle down.WindowState win = mFocusedWindow != null ? mFocusedWindow :mTopFullscreenOpaqueWindowState;if (win == null){return 0; }if (win.getAttrs().type == TYPE_KEYGUARD&&mHideLockScreen == true) {// We are updating at a pointwhere the keyguard has gotten// focus, but we were last in astate where the top window is// hiding it. This is probably because the keyguardas been// shown while the top window wasdisplayed, so we want to ignore// it here because this is just avery transient change and it// will quickly lose focus once itcorrectly gets hidden.return 0; } inttmpVisibility = win.getSystemUiVisibility()& ~mResettingSystemUiFlags& ~mForceClearedSystemUiFlags;if (mForcingShowNavBar&&win.getSurfaceLayer()<mForcingShowNavBarLayer) {tmpVisibility&= ~View.SYSTEM_UI_CLEARABLE_FLAGS; }finalint visibility = updateSystemBarsLw(win,mLastSystemUiFlags,tmpVisibility);finalint diff = visibility ^ mLastSystemUiFlags;finalbooleanneedsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);if (diff == 0 &&mLastFocusNeedsMenu == needsMenu&&mFocusedApp ==win.getAppToken()) {return 0; }mLastSystemUiFlags = visibility;mLastFocusNeedsMenu = needsMenu;mFocusedApp = win.getAppToken();mHandler.post(new Runnable() {@Overridepublicvoid run() {try {IStatusBarServicestatusbar = getStatusBarService();if (statusbar != null) {statusbar.setSystemUiVisibility(visibility,0xffffffff);statusbar.topAppWindowChanged(needsMenu); } } catch (RemoteException e) {// re-acquire status bar servicenext time it is needed.mStatusBarService = null; } } });return diff; }
C) Interception and distribution of various key events (for example, long-Press the home key)
The Home key event is intercepted at the phonewindow layer. Therefore, the application itself cannot normally intercept the event.
privatevoidhandleLongPressOnHome() {if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {mHomeConsumed = true;performHapticFeedbackLw(null,HapticFeedbackConstants.LONG_PRESS, false); if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {toggleRecentApps(); } elseif (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST){launchAssistAction(); } } }
D. Lock screen event handling and response
publicvoidsystemReady() {if (!mHeadless){mKeyguardDelegate = newKeyguardServiceDelegate(mContext, null);mKeyguardDelegate.onSystemReady(); }synchronized (mLock){updateOrientationListenerLp();mSystemReady = true;mHandler.post(new Runnable() {@Overridepublicvoid run() {updateSettings(); } }); }}
2. KeyguardServiceDelegate. java and KeyguardServiceWrapper. java
These two classes are newly added in android 4.4, which proxy and packaging the KeyguardService respectively. A Scrim view in the proxy class is displayed when keyguard crashes. The packaging class is a simple packaging of keyguardService, And the scheduling will be passed to keyguardService.
3. keyguardService. java
The class has been mentioned again and again, so what is its outstanding position? In fact, it is the keyguard entrance, and all the history of the screen lock starts with it. This class is very simple, and an IKeyguardService is instantiated. stub is called for other classes of bindservice. It is important to note that KeyguardViewMediator, the core strength of keyguard, is born here.
4. KeyguardViewMediator. java
Literally, the keyguard View Scheduler is responsible for processing events in the keyguard view, such as the view response for completing screen lock and unlocking these actions, as a high-weight scheduling, it certainly does not do this by itself. It has the ability to delegate KeyguardviewManager to all major and minor tasks.
/*** The dispatcher of the lock request. Including the query of the screen lock status, whether the screen lock should be displayed or reset is affected by the power management event, and the specific callback function * notifies the windowmanager when the screen lock is displayed, and the acceptance of the message sent from the view indicates that the unlocking has been completed successfully. * Please note that the screen lock is displayed immediately after the screen is disabled. In this way, when you light the screen, the screen lock will be displayed immediately. * For example, external event lock scheduling view process: **-screen removal action-reset the screen lock and display it to prepare for the next screen lighting. *-The screen lock is opened smoothly.-If it is not safe, hide it. ** Events from the screen lock view: *-when the user successfully completes the unlock condition-hide the screen lock view and no longer block the input events. * Please note that a third-party application can use a power management instance to block the lock screen of the system. ** Thread and synchronization: * this class is created and run in the thread of WindowManagerPolicy. The screen lock UI is also generated in the constructor of this class. This apis can also be called by other threads. * However, this method synchronizes gestures, and any screen lock view sends messages to handle to ensure that it is executed in the screen lock UI thread. */Public class KeyguardViewMediatorimplements KeyguardViewCallback, KeyguardUpdateMonitor. infoCallback, KeyguardUpdateMonitor. simStateCallback {private static final intKEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;/*** This handler will be associated with the policy thread, which willalso * be the UI thread of the keyguard. since the apis of the policy, and therefore * this class, can be called By other threads, any action that directly * interacts with the keyguard ui shoshould be posted to this handler, rather * than called directly. */private Handler mHandler = new Handler () {@ Override public void handleMessage (Message msg) {switch (msg. what) {case TIMEOUT: handleTimeout (msg. arg1); return; case SHOW: handleShow (); return; case HIDE: handleHide (); return; case RESET: handleReset (); Return; case VERIFY_UNLOCK: handleVerifyUnlock (); return; case policy_screen_off: handleNotifyScreenOff (); return; case policy_screen_on: handleNotifyScreenOn (KeyguardViewManager. showListener) msg. obj); return; case WAKE_WHEN_READY: handleWakeWhenReady (msg. arg1); return; case KEYGUARD_DONE: handleKeyguardDone (msg. arg1! = 0); return; case KEYGUARD_DONE_DRAWING: handleKeyguardDoneDrawing (); return; rows: keyguardDone (true); return; case SET_HIDDEN: handleSetHidden (msg. arg1! = 0); break; case KEYGUARD_TIMEOUT: synchronized (KeyguardViewMediator. this) {doKeyguardLocked () ;}}}; private void adjustStatusBarLocked (){...... // control whether the status bar can be pulled down on the screen lock page. }}
5. KeyguardViewManager. java
If mediator is equivalent to the President, it is the manager and the boss of the view department. It has an internal class named ViewManager in FrameLayout, which is used as the viewroot of keyguard. KeyguardHostView is added to viewroot, which is called mKeyguardView. Any view Details and problems in Keyguard can be traced through it.
/** * Manages creating, showing, hiding andresetting the keyguard. Callsback * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke * the wake lock and report that the keyguardis done, which is in turn, * reported to this class by the current {@link KeyguardViewBase}. */public class KeyguardViewManager { private final static boolean DEBUG = KeyguardViewMediator.DEBUG; private static String TAG = "KeyguardViewManager"; public static boolean USE_UPPER_CASE = true; public final static String IS_SWITCHING_USER = "is_switching_user"; // Timeoutused for keypresses static final int DIGIT_PRESS_WAKE_MILLIS = 5000; private final Context mContext; private final ViewManager mViewManager; private final KeyguardViewMediator.ViewMediatorCallbackmViewMediatorCallback; private WindowManager.LayoutParams mWindowLayoutParams; private boolean mNeedsInput = false; private ViewManagerHost mKeyguardHost; private KeyguardHostView mKeyguardView;
6. KeyguardHostVIew. java
The keyguardView layout is completed and instantiated. To analyze a custom viewgroup, we need to analyze its constructor and onFinishInflate () methods:
public KeyguardHostView(Context context, AttributeSet attrs) { super(context, attrs); if (DEBUG) Log.e(TAG, "KeyguardHostView()"); mLockPatternUtils = newLockPatternUtils(context); // Note: This depends on KeyguardHostView getting reconstructed every timethe // user switches, since mUserId will be used for the entire session. // Once created, keyguard should *never* re-use this instance withanother user. // In other words, mUserId should never change - hence it's marked final. mUserId = mLockPatternUtils.getCurrentUser(); DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); if (dpm != null) { mDisabledFeatures =getDisabledFeatures(dpm); mCameraDisabled =dpm.getCameraDisabled(null); } mSafeModeEnabled= LockPatternUtils.isSafeModeEnabled(); // These need to be created with the user context... Context userContext = null; try { final String packageName = "system"; userContext = mContext.createPackageContextAsUser(packageName,0, new UserHandle(mUserId)); } catch (NameNotFoundException e) { e.printStackTrace(); // This should never happen, but it's better to have no widgets than tocrash. userContext = context; } mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper()); mAppWidgetManager =AppWidgetManager.getInstance(userContext); mSecurityModel = new KeyguardSecurityModel(context); mViewStateManager = newKeyguardViewStateManager(this); } @Override protected void onFinishInflate() { // Grab instances of and make any necessary changes to the main layouts.Create // view state manager and wire up necessary listeners / callbacks. View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target); mAppWidgetContainer =(KeyguardWidgetPager) findViewById(R.id.app_widget_container); mAppWidgetContainer.setVisibility(VISIBLE); mAppWidgetContainer.setCallbacks(mWidgetCallbacks); mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget); mAppWidgetContainer.setMinScale(0.5f); mSlidingChallengeLayout =(SlidingChallengeLayout) findViewById(R.id.sliding_layout); if (mSlidingChallengeLayout != null) { mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager); } mAppWidgetContainer.setViewStateManager(mViewStateManager); mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils); mMultiPaneChallengeLayout = (MultiPaneChallengeLayout)findViewById(R.id.multi_pane_challenge); ChallengeLayout challenge =mSlidingChallengeLayout != null ? mSlidingChallengeLayout : mMultiPaneChallengeLayout; challenge.setOnBouncerStateChangedListener(mViewStateManager); mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration()); mViewStateManager.setPagedView(mAppWidgetContainer); mViewStateManager.setChallengeLayout(challenge); mSecurityViewContainer = (KeyguardSecurityViewFlipper)findViewById(R.id.view_flipper); mKeyguardSelectorView =(KeyguardSelectorView) findViewById(R.id.keyguard_selector_view); mViewStateManager.setSecurityViewContainer(mSecurityViewContainer); setBackButtonEnabled(false); if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()){ updateAndAddWidgets(); } else { // We can't add widgets until after boot completes because AppWidgetHostmay try // to contact the providers. Do itlater. mPostBootCompletedRunnable = new Runnable() { @Override public void run() { updateAndAddWidgets(); } }; } showPrimarySecurityScreen(false); updateSecurityViews(); enableUserSelectorIfNecessary(); }
7. KeyguardUpdateMonitor. java
Note: Changes in the monitoring system status value, such as time, SIM card status, and battery usage. Changes in the status value will call back and listen to the object instance of this status information. If you only want to focus on the function, you only need to check the method of calling each message in hadle.
/*** Watches for updates that may be interesting to the keyguard, and provides * the up to date information as well as a registration for callbacks that care * tobe updated. ** Note: under time crunch, this has been extended to include some stuff that * doesn't really belong here. see {@ link # handleBatteryUpdate} where it shutdowns * the device, and {@ link # getFailedAttempts ()}, {@ link # reportFailedAtt Empt ()} * and {@ link # clearFailedAttempts ()}. maybe we shoshould rename this 'keyguardcontext '... */public class KeyguardUpdateMonitor {private Handler mHandler; private ContentObserver mContentObserver; private int mRingMode; private int mPhoneState ;...... /*** SIM card status change capture assignment. * The intent and provide a {@ link SimCard. State} result. */private static class SimArgs {public final IccCard. State simState; private SimArgs (Intent intent) {if (! TelephonyIntents. ACTION_SIM_STATE_CHANGED.equals (intent. getAction () {throw newIllegalArgumentException ("only handles intentACTION_SIM_STATE_CHANGED");} String stateExtra = intent. getStringExtra (IccCard. INTENT_KEY_ICC_STATE); if (IccCard. INTENT_VALUE_ICC_ABSENT.equals (stateExtra) {final String absentReason = intent. getStringExtra (IccCard. INTENT_KEY_LOCKED_REASON); if (IccCard. INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals (absentReason) {this. simState = IccCard. state. PERM_DISABLED;} else {this. simState = IccCard. state. ABSENT ;}} else if (IccCard. INTENT_VALUE_ICC_READY.equals (stateExtra) {this. simState = IccCard. state. READY;} else if (IccCard. INTENT_VALUE_ICC_LOCKED.equals (stateExtra) {final String lockedReason = intent. getStringExtra (IccCard. INTENT_KEY_LOCKED_REASON); if (IccCard. INTENT_VALUE_LOCKED_ON_PIN.equals (lockedReason) {this. simState = IccCard. state. PIN_REQUIRED;} else if (IccCard. INTENT_VALUE_LOCKED_ON_PUK.equals (lockedReason) {this. simState = IccCard. state. PUK_REQUIRED;} else {this. simState = IccCard. state. UNKNOWN;} else if (IccCard. INTENT_VALUE_LOCKED_NETWORK.equals (stateExtra) {this. simState = IccCard. state. NETWORK_LOCKED;} else {this. simState = IccCard. state. UNKNOWN ;}} public String toString () {return simState. toString () ;}} public KeyguardUpdateMonitor (Context context) {mContext = context; mHandler = new Handler () {@ Override public void handleMessage (Message msg) {switch (msg. what) {case MSG_TIME_UPDATE: handleTimeUpdate (); break; case MSG_BATTERY_UPDATE: handleBatteryUpdate (msg. arg1, msg. arg2); break; caseMSG_CARRIER_INFO_UPDATE: handleCarrierInfoUpdate (); break; case MSG_SIM_STATE_CHANGE: handleSimStateChange (SimArgs) msg. obj); break; caseMSG_RINGER_MODE_CHANGED: handleRingerModeChange (msg. arg1); break; caseMSG_PHONE_STATE_CHANGED: handlePhoneStateChanged (String) msg. obj); break; caseMSG_CLOCK_VISIBILITY_CHANGED: handleClockVisibilityChanged (); break; caseMSG_DEVICE_PROVISIONED: handleDeviceProvisioned (); break ;}}};