Android4.4 锁屏流程梳理
刚毕业不久由于项目需要就接触到锁屏,从2.2到4.1都解过bug,也定制过一些功能。4.1之前的锁屏工作不难,但很费时间,因为它的逻辑,视图,资源分别分布在不同的路径下,就像散落在海边沙滩上的珠子,想串起来还是蛮费劲的。最开始时锁屏就是改个字段也要全编译生成img。后来新技能get,会针对修改的地方进行单编译,但每次编译jar,导入手机,重启看效果也是不方便的。
一年前把锁屏交出去就没有再看过了,前些日子自己的谷歌四太子升到4.4,发现锁屏有很大变化,可以左右滑页,添加删除widget,添加删除分页。简直就是一个简化版的launcher。很好奇google是怎么改变的,于是费了很大的劲拉了google的最新源码。在android 4.4中这个模块的改动简直是巨大,这里略作整理。
1.文件目录:
a,锁屏代理是在Frameworks/base/policy/src/com/android/internal/policy/impl/keyguard下:
b,整个工程应用在framework/package下,结构和功能现在都和 systemUI类似:
c,keyguard的对外接口Frameworks/base/core/java/android/app/keyguardManager.java:
android4.2前做一些第三方锁屏软件都会用到该服务接口来控制系统锁屏(比如禁止系统锁屏),现在该接口已经不建议使用了,有更好的做法:
-
-
-
-
-
-
-
-
-
-
-
-
-
- @Deprecated
- public KeyguardLock newKeyguardLock(Stringtag) {
- return new KeyguardLock(tag);
- }
Keyguard锁屏流程图
Keyguard锁屏view层次图:
Keyguard锁屏重要类分析:
1.PhoneWindowManager.java
这个类很厉害也很重要,它由WindowManagerService派生,处理了phone的顶层逻辑,主要有以下几块:
a) 横竖屏处理(屏幕旋转等)
- publicvoidsetCurrentOrientationLw(intnewOrientation){
- synchronized (mLock){
- if (newOrientation != mCurrentAppOrientation) {
- mCurrentAppOrientation = newOrientation;
- updateOrientationListenerLp();
- }
- }
- }
b) 是否显示状态条或者navigation_bar。
- privateintupdateSystemUiVisibilityLw() {
-
-
- WindowState win = mFocusedWindow != null ? mFocusedWindow :mTopFullscreenOpaqueWindowState;
- if (win == null){
- return 0;
- }
- if (win.getAttrs().type == TYPE_KEYGUARD&&mHideLockScreen == true) {
-
-
-
-
-
-
- return 0;
- }
-
- inttmpVisibility = win.getSystemUiVisibility()
- & ~mResettingSystemUiFlags
- & ~mForceClearedSystemUiFlags;
- if (mForcingShowNavBar&&win.getSurfaceLayer()
- 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() {
- @Override
- publicvoid run() {
- try {
- IStatusBarServicestatusbar = getStatusBarService();
- if (statusbar != null) {
- statusbar.setSystemUiVisibility(visibility,0xffffffff);
- statusbar.topAppWindowChanged(needsMenu);
- }
- } catch (RemoteException e) {
-
- mStatusBarService = null;
- }
- }
- });
- return diff;
- }
c) 各种按键事件的拦截和分发(比如长按home键)
Home键的事件是在phonewindow这一层就拦截的,所以一般情况应用本身无法正常拦截该事件。
- 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) 锁屏事件处理和响应
- publicvoidsystemReady() {
- if (!mHeadless){
- mKeyguardDelegate = newKeyguardServiceDelegate(mContext, null);
- mKeyguardDelegate.onSystemReady();
- }
- synchronized (mLock){
- updateOrientationListenerLp();
- mSystemReady = true;
- mHandler.post(new Runnable() {
- @Override
- publicvoid run() {
- updateSettings();
- }
- });
- }
- }
2.KeyguardServiceDelegate.java和KeyguardServiceWrapper.java
这两个类是android 4.4新增加的,分别对KeyguardService进行了代理和包装,代理类里面有一个Scrim视图在keyguard崩溃时显示。包装类就是对keyguardService的简单包装,最终把调度都会传给keyguardService。
3.keyguardService.java
上面一再说到该类,那么它有啥出众的地方呢,其实它就是keyguard的入口,锁屏所有的往生都因它而起,这个类很简单,实例化了一个IKeyguardService.Stub供其他类bindservice时调用,需要特别注意的是整个keyguard的核心实力派KeyguardViewMediator在这里诞生了。
4.KeyguardViewMediator.java
字面上的意思是keyguard视图调度者,功能上是负责处理keyguard视图的事件,比如完成锁屏和解锁这些动作的视图响应,它作为一个位高权重的调度使当然不会亲手去做这些,它有个得力干将KeyguardviewManager,所有的大小任务都会放权给它。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class KeyguardViewMediatorimplements KeyguardViewCallback,
- KeyguardUpdateMonitor.InfoCallback,KeyguardUpdateMonitor.SimStateCallback {
- private static final intKEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
-
-
-
-
-
-
-
- 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 NOTIFY_SCREEN_OFF:
- handleNotifyScreenOff();
- return;
- case NOTIFY_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;
- caseKEYGUARD_DONE_AUTHENTICATING:
- keyguardDone(true);
- return;
- case SET_HIDDEN:
- handleSetHidden(msg.arg1 !=0);
- break;
- case KEYGUARD_TIMEOUT:
- synchronized(KeyguardViewMediator.this) {
- doKeyguardLocked();
- }
- break;
- }
- }
- };
- private void adjustStatusBarLocked() {
- ......
- }
- }
5.KeyguardViewManager.java
如果说mediator相当于总裁,那这个就是经理,而且是视图部门老大,它有一个类型为FrameLayout名叫ViewManagerHost的内部类,用来作为keyguard的viewroot。在viewroot里添加了KeyguardHostView,我们叫它mKeyguardView。Keyguard里任何的view细节和问题都能通过它找到蛛丝马迹。
-
-
-
-
-
-
- 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";
-
-
- 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
这里完成keyguardView布局,实例化。分析一个自定义的viewgroup,重点需要分析的是它的构造方法和onFinishInflate()方法:
- public KeyguardHostView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- if (DEBUG) Log.e(TAG, "KeyguardHostView()");
-
- mLockPatternUtils = newLockPatternUtils(context);
-
-
-
-
-
- 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();
-
-
- Context userContext = null;
- try {
- final String packageName = "system";
- userContext = mContext.createPackageContextAsUser(packageName,0,
- new UserHandle(mUserId));
-
- } catch (NameNotFoundException e) {
- e.printStackTrace();
-
- 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() {
-
-
- 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 {
-
-
- mPostBootCompletedRunnable = new Runnable() {
- @Override
- public void run() {
- updateAndAddWidgets();
- }
- };
- }
-
- showPrimarySecurityScreen(false);
- updateSecurityViews();
- enableUserSelectorIfNecessary();
- }
7.KeyguardUpdateMonitor.java
说明:监听系统状态值的改变如时间、SIM卡状态、电池电量等,状态值的改变会回调监听了该状态信息的对象实例。如果只是关注功能的话只需要看hadle里面的每个消息调用的方法即可。
-
-
-
-
-
-
-
-
-
-
- public class KeyguardUpdateMonitor {
- private Handler mHandler;
- private ContentObserver mContentObserver;
- private int mRingMode;
- private int mPhoneState;
- ......
-
-
-
-
-
- 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;
- }
- }
- };