本文主要是介绍android4.4的Keyguard心得,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在总结锁屏代码之前,有两个中心思想要铭记于心
A) KeyguardHostView就是我们最终所要展示的界面,所以不论用什么方法手段,都要将这个KeyguardHostView添加到窗口中,后续填充它,都是细节问题
B) 那么问题来了,通常我们将一个view添加到窗口中会用什么方法呢?
答案有两种 1 WindowManager.addView() 2 LayoutInflater.inflate(resID, parentView, true); 而在锁屏代码中这两种方法都有用到
-----------------------------------------------华丽丽的分割线-------------------------------------------------------------------
接下来用一张图来解释流程
-------------------------------又是可爱的分割线--------------------------------------------------------
从图中可以看到, 开机后首先从PhoneWindowManager的systemReady方法调用两个包装类(KeyguardServiceDelegate.java KeyguardServiceWrapper.java)之后会调用到KeyguardService.java中的onSystemReady,进而调用锁屏代码的总调度使KeyguardViewMediator.java。它就是锁屏的CEO。做我们软件的都知道,CEO一般不会太牵涉代码问题,只管分配,协调工作,客户/供应链的沟通。在KeyguardViewMediator.java中的mExternallyEnabled变量就是总监与客户谈判的筹码,如果客户第三方通过KeyguardManager.diableKeyguard()方法禁用系统锁屏后,此变量会置为false,从而不会绘制系统锁屏界面,otherwise,将任务大手一甩直接丢给总经理KeyguardViewManager.java.具体代码如下:
- <span style="font-size:12px;"> /**
- * Enable the keyguard if the settings are appropriate.
- */
- private void doKeyguardLocked(Bundle options) {
- boolean isSimSecure = mUpdateMonitor.isSimPinSecure();
- ///M: if another app is disabling us (except Sim Secure), then don't show
- if ((!mExternallyEnabled && !isSimSecure)|| PowerOffAlarmManager.isAlarmBoot()) {
- if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: not showing because externally disabled");
- return;
- }
- 。。。
- showLocked(options);
- }
- private void handleShow(Bundle options) {
- 。。。
- mKeyguardViewManager.show(options);
- 。。。
- }
- 通过以上代码,所有的任务都已经落实到KeyguardViewManager.java的头上,接下来看看这个总经理是如何工作的
- /**
- * Show the keyguard. Will handle creating and attaching to the view manager
- * lazily.
- */
- public synchronized void show(Bundle options) {
- if (DEBUG) Log.d(TAG, "show(); mKeyguardView=" + mKeyguardView);
- boolean enableScreenRotation = KeyguardUtils.shouldEnableScreenRotation(mContext);
- if (DEBUG) Log.d(TAG, "show() query screen rotation after");
- /// M: Incoming Indicator for Keyguard Rotation @{
- KeyguardUpdateMonitor.getInstance(mContext).setQueryBaseTime();
- /// @}
- <span style="color:#FF0000;">maybeCreateKeyguardLocked(enableScreenRotation, false, options);</span>
- if (DEBUG) Log.d(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.
- int visFlags = View.STATUS_BAR_DISABLE_HOME;
- if (shouldEnableTranslucentDecor()) {
- mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
- }
- if (DEBUG) Log.d(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")");
- mKeyguardHost.setSystemUiVisibility(visFlags);
- mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
- mKeyguardHost.setVisibility(View.VISIBLE);
- <span style="color:#FF0000;">mKeyguardView.show();</span>
- mKeyguardView.requestFocus();
- if (DEBUG) Log.d(TAG, "show() exit; mKeyguardView=" + mKeyguardView);
- }
- 关键代码所以全部贴出来分析分析吧,
- <span style="color:#009900;">//有一点需要提前注意mKeyguardHost只是一个空View,mKeyguardView才是真正的KeyguardHostView</span>
- boolean enableScreenRotation用来判断是否允许屏幕旋转,
- KeyguardUpdateMonitor.getInstance(mContext).setQueryBaseTime();此行代码是为了重新设置query的时间,比如未接来电,未读短信等,之所以重新set是为了仿照
- iphone手机,绘制锁屏时,查询未读信息/未接电话的数目是针对本次锁屏后收到的未读信息/未接电话
- maybeCreateKeyguardLocked(enableScreenRotation, false, options); 我擦~终于到关键代码了,此方法就是真正创建锁屏的方法,来一睹芳容吧
- private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
- Bundle options) {
- if (mKeyguardHost != null) {
- mKeyguardHost.saveHierarchyState(mStateContainer);
- }
- if (mKeyguardHost == null) {
- if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
- <span style="color:#990000;">mKeyguardHost = new ViewManagerHost(mContext);</span>
- 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;
- if (!mNeedsInput) {
- flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
- final int type = 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 = R.style.Animation_LockScreen;
- lp.screenOrientation = enableScreenRotation ?
- ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
- 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;
- /// M: Poke user activity when operating Keyguard
- //lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
- lp.setTitle("Keyguard");
- mWindowLayoutParams = lp;
- ///M: skip add KeyguardHost into viewManager in AT case
- if (!KeyguardViewMediator.isKeyguardInActivity) {
- <span style="color:#CC0000;">mViewManager.addView(mKeyguardHost, lp);</span>
- } else {
- if (DEBUG) Log.d(TAG, "skip add mKeyguardHost into mViewManager for testing");
- }
- KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mBackgroundChanger);
- }
- /// 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) {
- mKeyguardHost.setCustomBackground(null);
- mKeyguardHost.removeAllViews();
- <span style="color:#CC0000;">inflateKeyguardView(options);</span>
- mKeyguardView.requestFocus();
- }
- updateUserActivityTimeoutInWindowLayoutParams();
- mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
- mKeyguardHost.restoreHierarchyState(mStateContainer);
- }
然后在通过 inflateKeyguardView(options); 方法将真正的KeyguardHostView也添加到mKeyguardHost中, 具体如何添加请看代码:
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(PowerOffAlarmManager.isAlarmBoot()){
resId = R.id.power_off_alarm_host_view;
layoutId = R.layout.mtk_power_off_alarm_host_view;
}
/// @}
View v = mKeyguardHost.findViewById(resId);
if (v != null) {
mKeyguardHost.removeView(v);
}
/// M: Save new orientation
mCreateOrientation = mContext.getResources().getConfiguration().orientation;
mCreateScreenWidthDp = mContext.getResources().getConfiguration().screenWidthDp;
mCreateScreenHeightDp = mContext.getResources().getConfiguration().screenHeightDp;
final LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(layoutId, mKeyguardHost, true);
mKeyguardView = (KeyguardHostView) view.findViewById(resId);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
mKeyguardView.initializeSwitchingUserState(options != null &&
options.getBoolean(IS_SWITCHING_USER));
// 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) {
// Start of cube26 code
if (mLockscreenNotifications)
mNotificationView.setViewMediator(mViewMediatorCallback);
// End of cube26 code
KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
R.id.keyguard_password_view);
if (kpv != null) {
mViewMediatorCallback.setNeedsInput(kpv.needsInput());
}
}
if (options != null) {
int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
mKeyguardView.goToWidget(widgetToShow);
}
}
}
红色标记处,通过LayoutInflater.inflate(resId, parentView, true)的方式将 R.layout.keyguard_host_view 添加到mKeyguardHost这个空view中
自此真正的KeyguardHostView已经添加到窗口中,并且通过各中layoutparam将其显示在最上层,后续的就是如何将其显示,使用何种方式显示,比如Slide,Swipe,Password
等等,这些都是细节,后续博客中将继续分析
这篇关于android4.4的Keyguard心得的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!