Android4.2锁屏流程【Android锁屏解析三】
来源:互联网 发布:在淘宝上买女士秋衣 编辑:程序博客网 时间:2024/05/19 02:18
谷歌对Android4.2的版本做了一些改动,突出的改动就是锁屏可以添加widget,即锁屏widget,这个是谷歌的一个大的改动,先来说说android4.2做了哪些改动?
(1)Lock screen widgets如图:
(2)屏保模式的添加
简单介绍如下:互助屏保是一个互动屏幕保护程序模式,当用户的设备开始停靠或充电。在这种模式下,系统将启动一枕黄粱 - 远程安装的应用程序提供内容服务 - 设备的屏幕保护程序。用户可以设置应用程序启用白日梦,然后选择显示遐想。
(3)更多显示的支持
(4)Native RTL support从右向左支持,例如印度语,就是这种显示格式。
等等,更多特性请参考官网:http://developer.android.com/about/versions/jelly-bean.html#42-external-display
好了,言归正传,我们来说说Android4.2锁屏的流程:咱们一步一步来说:
Step1:先看第一次开机的加载锁屏的过程,通过PhoneWindowManager.java这个类的systemReady()这个方法,当系统开机准备好的情况下会调用这个方法,如下:
public void systemReady() { if (mKeyguardMediator != null) { // tell the keyguard mKeyguardMediator.onSystemReady(); } synchronized (mLock) { updateOrientationListenerLp(); mSystemReady = true; mHandler.post(new Runnable() { public void run() { updateSettings(); } }); } }
Step2:看注释就知道下一步该干什么了,告诉锁屏的管理者,我准备好了,该你来控制加载锁屏界面了。接着调用到了KeyguardViewMediator.java这个类的onSystemReady()方法,如下:
/** * Let us know that the system is ready after startup. */ public void onSystemReady() { mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); mSystemReady = true; mUpdateMonitor.registerCallback(mUpdateCallback); // Suppress biometric unlock right after boot until things have settled if it is the // selected security method, otherwise unsuppress it. It must be unsuppressed if it is // not the selected security method for the following reason: if the user starts // without a screen lock selected, the biometric unlock would be suppressed the first // time they try to use it. // // Note that the biometric unlock will still not show if it is not the selected method. // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the // selected method. if (mLockPatternUtils.usingBiometricWeak() && mLockPatternUtils.isBiometricWeakInstalled() || mLockPatternUtils.usingVoiceWeak() && FeatureOption.MTK_VOICE_UNLOCK_SUPPORT) { if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot"); mUpdateMonitor.setAlternateUnlockEnabled(false); } else { mUpdateMonitor.setAlternateUnlockEnabled(true); } /// M: power-off alarm @{ if (!KeyguardUpdateMonitor.isAlarmBoot()) { doKeyguardLocked(); } /// @} } // Most services aren't available until the system reaches the ready state, so we // send it here when the device first boots. maybeSendUserPresentBroadcast(); }
Step3:接着由doKeyguardLocked()这个方法来做启动锁屏界面的预处理,来看看这个方法都做了什么:
private void doKeyguardLocked() { doKeyguardLocked(null); } /** * Enable the keyguard if the settings are appropriate. */ private void doKeyguardLocked(Bundle options) { // if another app is disabling us, don't show if (!mExternallyEnabled || KeyguardUpdateMonitor.isAlarmBoot()) { if (DEBUG) KeyguardUtils.xlogD(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; } // if the keyguard is already showing, don't bother if (mKeyguardViewManager.isShowing()) { if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: not showing because it is already showing"); return; } // if the setup wizard hasn't run yet, don't show if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: get keyguard.no_require_sim property before"); final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false); if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: get keyguard.no_require_sim property after"); final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); final IccCardConstants.State state = mUpdateMonitor.getSimState(); boolean lockedOrMissing = false; /// M: Support GeminiPlus for (int i = PhoneConstants.GEMINI_SIM_1; i <= KeyguardUtils.getMaxSimId(); i++) { lockedOrMissing = (lockedOrMissing || isLockedOrMissingGemini(i, requireSim)); if (lockedOrMissing) { break; } } if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: get sim state after"); /// M: MTK MOTA UPDATE when on ics2 keygaurd set none,update to JB,the keyguard will show LockScreen. /// MTK MOTA UPDATE when the phone first boot,check the settingDB mirged or not ,because mota update, /// the settingdb migrate slow than keygaurd(timing sequence problem) @{ boolean keyguardDisable = false; /////*************************************TODO boolean motaUpdateFirst = true;//mLockPatternUtils.isDbMigrated(); if (motaUpdateFirst) { /// DB mogi done keyguardDisable = mLockPatternUtils.isLockScreenDisabled(); } else { /// DB not mogi final ContentResolver cr = mContext.getContentResolver(); String value = Settings.Secure.getString(cr, "lockscreen.disabled"); boolean booleanValue = false; if( null!=value ){ booleanValue = value.equals("1") ? true :false; } keyguardDisable = (!mLockPatternUtils.isSecure()) && booleanValue; } /// @} if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: keyguardDisable query end"); /// M: Add new condition DM lock is not true boolean dmLocked = KeyguardUpdateMonitor.getInstance(mContext).dmIsLocked(); KeyguardUtils.xlogD(TAG, "lockedOrMissing is " + lockedOrMissing + ", requireSim=" + requireSim + ", provisioned=" + provisioned + ", keyguardisable=" + keyguardDisable + ", dmLocked=" + dmLocked); if (!lockedOrMissing && !provisioned && !dmLocked) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + " and the sim is not locked or missing"); return; } /// M: Add a new condition DM lock is not on, or user can still bypass dm lock when Keygaurd is disabled if (mUserManager.getUsers(true).size() < 2 && keyguardDisable && !lockedOrMissing && !KeyguardUpdateMonitor.getInstance(mContext).dmIsLocked()) { 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); }
Step4、来注意最后调用的这个方法showLocked(options),这个方法是启动锁屏关键的方法,来看看:
/** * Send message to keyguard telling it to show itself * @see #handleShow() */ private void showLocked(Bundle options) { if (DEBUG) KeyguardUtils.xlogD(TAG, "showLocked"); // ensure we stay awake until we are finished displaying the keyguard mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW, options); mHandler.sendMessage(msg); }
Step5、这下就通过发送消息来进一步启动锁屏界面,来看看这个mHandler中的SHOW都做了什么:
public void handleMessage(Message msg) { if (DBG_MESSAGE) KeyguardUtils.xlogD(TAG, "handleMessage enter msg name=" + getMessageString(msg)); switch (msg.what) { case SHOW: handleShow((Bundle) msg.obj); break;调用的是handleShow()这个方法:
/** * Handle message sent by {@link #showLocked}. * @see #SHOW */ private void handleShow(Bundle options) { synchronized (KeyguardViewMediator.this) { if (DEBUG) KeyguardUtils.xlogD(TAG, "handleShow enter"); if (!mSystemReady) return; /// M: if already showing, just return if (mShowing) return; mKeyguardViewManager.show(options); if (DEBUG) KeyguardUtils.xlogD(TAG, "handleShow mKeyguardViewManager Show exit"); mShowing = true; mKeyguardDonePending = false; updateActivityLockScreenState(); adjustStatusBarLocked(); userActivity(); try { ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { } if (DEBUG) KeyguardUtils.xlogD(TAG, "handleShow query AlarmBoot before"); // Do this at the end to not slow down display of the keyguard. if (!KeyguardUpdateMonitor.isAlarmBoot()) { playSounds(true); } else { new Handler().postDelayed(new Runnable() { public void run() { sendRemoveIPOWinBroadcast(); startAlarm(); } }, 250); } mShowKeyguardWakeLock.release(); if (DEBUG) KeyguardUtils.xlogD(TAG, "handleShow exit"); } }
Step6、接着看mKeyguardViewManager.show(options);这个方法都干了什么:
/** * Show the keyguard. Will handle creating and attaching to the view manager * lazily. */ public synchronized void show(Bundle options) { if (DEBUG) KeyguardUtils.xlogD(TAG, "show(); mKeyguardView=" + mKeyguardView); boolean enableScreenRotation = shouldEnableScreenRotation(); if (DEBUG) KeyguardUtils.xlogD(TAG, "show() query screen rotation after"); /// M: Incoming Indicator for Keyguard Rotation @{ KeyguardUpdateMonitor.getInstance(mContext).setQueryBaseTime(); /// @} maybeCreateKeyguardLocked(enableScreenRotation, false, options); if (DEBUG) KeyguardUtils.xlogD(TAG, "show() maybeCreateKeyguardLocked finish"); maybeEnableScreenRotation(enableScreenRotation); // Disable common aspects of the system/status/navigation bars that are not appropriate or // useful on any keyguard screen 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. final int visFlags = View.STATUS_BAR_DISABLE_HOME; if (DEBUG) KeyguardUtils.xlogD(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")"); mKeyguardHost.setSystemUiVisibility(visFlags); mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); mKeyguardHost.setVisibility(View.VISIBLE); mKeyguardView.show(); mKeyguardView.requestFocus(); if (DEBUG) KeyguardUtils.xlogD(TAG, "show() exit; mKeyguardView=" + mKeyguardView); }
Step7,、这下终于看到如山真面目了,看里面的方法maybeCreateKeyguardLocked()这个是真正起作用的地方:
private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force, Bundle options) { final boolean isActivity = (mContext instanceof Activity); // for test activity if (mKeyguardHost != null) { mKeyguardHost.saveHierarchyState(mStateContainer); } if (mKeyguardHost == null) { if (DEBUG) KeyguardUtils.xlogD(TAG, "keyguard host is null, creating it..."); mKeyguardHost = new ViewManagerHost(mContext); int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; /// M: Modify to support DM lock, hide statusbr when dm lock power on @{ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); if (monitor.dmIsLocked()) { //in the first created if (DEBUG) KeyguardUtils.xlogD(TAG, "show(); dmIsLocked "); flags &= ~WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; flags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; } else if (KeyguardUpdateMonitor.isAlarmBoot()) { if (DEBUG) KeyguardUtils.xlogD(TAG, "show(); AlarmBoot "); flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; flags |= WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; } /// M: @} if (!mNeedsInput) { flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } if (ActivityManager.isHighEndGfx()) { flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; final int type = isActivity ? WindowManager.LayoutParams.TYPE_APPLICATION : WindowManager.LayoutParams.TYPE_KEYGUARD; WindowManager.LayoutParams lp = new WindowManager.LayoutParams( stretch, stretch, type, flags, PixelFormat.TRANSLUCENT); lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; if (ActivityManager.isHighEndGfx()) { lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; } lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY; if (isActivity) { lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; } /// M: Poke user activity when operating Keyguard //lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; lp.setTitle(isActivity ? "KeyguardMock" : "Keyguard"); mWindowLayoutParams = lp; mViewManager.addView(mKeyguardHost, lp); } /// M: If force and keyguardView is not null, we should relase memory hold by old keyguardview if (force && mKeyguardView != null) { mKeyguardView.cleanUp(); } if (force || mKeyguardView == null) { inflateKeyguardView(options); mKeyguardView.requestFocus(); } updateUserActivityTimeoutInWindowLayoutParams(); mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); mKeyguardHost.restoreHierarchyState(mStateContainer); }
这下通过 mViewManager.addView(mKeyguardHost, lp);这个方法真正地把锁屏界面添加到屏幕上,其实这个就是个view,挡在了手机的屏幕的最上方。而这个mKeyguardHost就是锁屏的根。而第一次加载的时候mKeyguardView为空,调用inflateKeyguardView(),初始化锁屏的view。Step8、来看看这个inflateKeyguardView()这个方法都加载了哪个布局:
private void inflateKeyguardView(Bundle options) { /// M: add for power-off alarm @{ int resId = R.id.keyguard_host_view; int layoutId = R.layout.keyguard_host_view; if(KeyguardUpdateMonitor.isAlarmBoot()){ layoutId = com.mediatek.internal.R.layout.power_off_alarm_host_view; resId = com.mediatek.internal.R.id.keyguard_host_view; } /// @} View v = mKeyguardHost.findViewById(resId); if (v != null) { mKeyguardHost.removeView(v); } // TODO: Remove once b/7094175 is fixed if (false) Slog.d(TAG, "inflateKeyguardView: b/7094175 mContext.config=" + mContext.getResources().getConfiguration()); /// M: Save new orientation mCreateOrientation = mContext.getResources().getConfiguration().orientation; final LayoutInflater inflater = LayoutInflater.from(mContext); View view = inflater.inflate(layoutId, mKeyguardHost, true); mKeyguardView = (KeyguardHostView) view.findViewById(resId); mKeyguardView.setLockPatternUtils(mLockPatternUtils); mKeyguardView.setViewMediatorCallback(mViewMediatorCallback); // HACK // The keyguard view will have set up window flags in onFinishInflate before we set // the view mediator callback. Make sure it knows the correct IME state. if (mViewMediatorCallback != null) { KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById( R.id.keyguard_password_view); if (kpv != null) { mViewMediatorCallback.setNeedsInput(kpv.needsInput()); } } /// Extract this block to a single function updateKeyguardViewFromOptions(options); }这个加载了keyguard_host_view这个layout,来看看这个布局是怎么写的:
<com.android.internal.policy.impl.keyguard.KeyguardHostView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/res/android" android:id="@+id/keyguard_host_view" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical"> <com.android.internal.policy.impl.keyguard.SlidingChallengeLayout android:id="@+id/sliding_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" androidprv:layout_childType="mediatekLayerBackground"> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" androidprv:layout_childType="pageDeleteDropTarget"> <include layout="@layout/keyguard_widget_remove_drop_target" android:id="@+id/keyguard_widget_pager_delete_target" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center_horizontal" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" androidprv:layout_childType="widgets"> <include layout="@layout/keyguard_widget_pager" android:id="@+id/app_widget_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center"/> </FrameLayout> <View android:layout_width="match_parent" android:layout_height="match_parent" androidprv:layout_childType="scrim" android:background="#99000000" /> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" androidprv:layout_childType="mediatekLayerForeground"> </FrameLayout> <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer android:id="@+id/keyguard_security_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_maxHeight="@dimen/keyguard_security_height" androidprv:layout_childType="challenge" android:padding="0dp" android:gravity="bottom|center_horizontal"> <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:paddingTop="@dimen/keyguard_security_view_margin" android:gravity="center"> </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper> </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer> <ImageButton android:layout_width="match_parent" android:layout_height="@dimen/kg_widget_pager_bottom_padding" androidprv:layout_childType="expandChallengeHandle" android:focusable="true" android:background="@null" android:src="@drawable/keyguard_expand_challenge_handle" android:scaleType="center" android:contentDescription="@string/keyguard_accessibility_expand_lock_area" /> </com.android.internal.policy.impl.keyguard.SlidingChallengeLayout></com.android.internal.policy.impl.keyguard.KeyguardHostView>而这个KeyguardHostView.java就是锁屏的真正的处理的view,该添加什么样的锁屏,例如:PIN,Pattern,PUK,Password等等,都是由它来控制的,最后会调用到getLayoutIdFor()这个方法,来启动那种锁屏界面,如下:
private int getLayoutIdFor(SecurityMode securityMode) { switch (securityMode) { case None: return R.layout.keyguard_selector_view; case Pattern: return R.layout.keyguard_pattern_view; case PIN: return R.layout.keyguard_pin_view; case Password: return R.layout.keyguard_password_view; case Biometric: return R.layout.keyguard_face_unlock_view; case Account: return R.layout.keyguard_account_view; /// M: Modify Sim unlock layout @{ //case SimPin: return R.layout.keyguard_sim_pin_view; //case SimPuk: return R.layout.keyguard_sim_puk_view; case SimPinPukMe1: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view; case SimPinPukMe2: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view; /// M: Support GeminiPlus case SimPinPukMe3: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view; case SimPinPukMe4: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view; /// @} /// M: power-off alarm @{ case AlarmBoot: return com.mediatek.internal.R.layout.power_off_alarm_view; /// @} ///M: add voice unlock view layout case Voice: return R.layout.zz_keyguard_voice_unlock_view; default: return 0; } }到这,锁屏已经初始化完了,要想下面接着分析,估计大家应该都能分析过去了;
特别说明:
1、加载锁屏widget的地方在KeyguardHostView.java的onFinishInflate()中,调用的addDefaultWidget()这个方法中添加了单click事件,最后调用到KeyguardActivityLauncher.java的launcherWidgetPicker()这个方法;
2、要想你写的widget能被锁屏widget过滤出来,只需要在wdget的xml中添加一个属性即可:
android:widgetCategory="home_screen|keyguard",这样你写的桌面widget,也能在锁屏wiget过滤出来,具体布局需要你微调下;
添加一张图,
- Android4.2锁屏流程【Android锁屏解析三】
- Android4.2锁屏流程【Android锁屏解析三】
- Android4.2锁屏流程【Android锁屏解析三】
- Android4.2锁屏流程【Android锁屏解析三】
- Android4.2锁屏流程【Android锁屏解析三】
- 王宪明的文章:Android4.2锁屏流程【Android锁屏解析三】
- Android4.4 锁屏流程梳理
- Android4.2 4.4keyguard锁屏流程梳理
- 浅析android锁屏开机绘制流程(基于android4.0源码分析)
- 浅析android锁屏开机绘制流程(基于android4.0源码分析) .
- Android4.0 4.1Keyguard锁屏流程梳理
- Android4.0 4.1Keyguard锁屏流程梳理(转)
- Android4.4 4.2keyguard锁屏流程梳理
- Android4.0 4.1Keyguard锁屏流程梳理
- Android4.4 4.2keyguard锁屏流程梳理
- Android4.4 4.2keyguard锁屏流程梳理
- Android4.4 4.2keyguard锁屏流程梳理
- Android4.4 4.2keyguard锁屏流程梳理
- keepalived源码浅析——Memory 内存管理
- Spring MVC 3.x 核心讲解
- Nginx进程管理
- 我的第一篇 实习报告
- Oracle触发器
- Android4.2锁屏流程【Android锁屏解析三】
- android vold流程分析
- S3C6410 中断
- 11G alert.log位置和 listener.log位置
- Unity3d 教程手册
- HDU 4608 I-number 解题报告
- VS2003里添加控件
- nmap使用方法
- hadoop资料