前面学习了SystemUI中状态栏模块相关内容,接下来学习锁屏模块相关内容,锁屏模块可以大致分为两个部分,一个是密码解锁,一个是页面加载,密码解锁是由KeyguardBouncer类控制,页面加载是在StatusBar中加载,个人认为页面之所以在StatusBar中加载是因为很多内容与状态栏重合
先从开机启动流程开始,手机开机后会启动SystemServer,后续调用startSystemUi方法
public static void main(String[] args) {
Log.d("sunyuke","启动SystemServer");
new SystemServer().run();
}
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Log.d("sunyuke","启动systemUI");
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
onSystemUiStarted方法实际是在PhoneWindowManager类中处理,手机按键大部分都是在PhoneWindowManager类中进行处理
@Override
public void onSystemUiStarted() {
bindKeyguard();
}
private void bindKeyguard() {
synchronized (mLock) {
if (mKeyguardBound) {
return;
}
mKeyguardBound = true;
}
mKeyguardDelegate.bindService(mContext);
}
后面会调用到KeyguardServiceDelegate类中的bindService,对KeyguardService进行绑定
public void bindService(Context context) {
Intent intent = new Intent();
final Resources resources = context.getApplicationContext().getResources();
final ComponentName keyguardComponent = ComponentName.unflattenFromString(
resources.getString(com.android.internal.R.string.config_keyguardComponent));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
intent.setComponent(keyguardComponent);
Log.d("sunyuke","绑定KeyguardService :"+intent.getComponent().getClassName());
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
mKeyguardState.secure = false;
synchronized (mKeyguardState) {
// TODO: Fix synchronisation model in this class. The other state in this class
// is at least self-healing but a race condition here can lead to the scrim being
// stuck on keyguard-less devices.
mKeyguardState.deviceHasKeyguard = false;
}
} else {
if (DEBUG) Log.v(TAG, "*** Keyguard started");
}
}
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
Log.d("sunyuke","将KeyguardServicer传入KeyguardServiceWrapper");
mKeyguardService = new KeyguardServiceWrapper(mContext,
IKeyguardService.Stub.asInterface(service), mCallback);
if (mKeyguardState.systemIsReady) {
// If the system is ready, it means keyguard crashed and restarted.
mKeyguardService.onSystemReady();
...
}
...
}
绑定成功后在ServiceConnection中进行回调,调用KeyguardService中的onSystemReady方法,最终会调用KeyguardViewMediator中的handleSystemReady方法,doKeyguardLocked是启动锁屏界面的预处理方法。主要处理有
1.判断其他应用禁止锁屏呈现。
2.判断是否需要重置状态。
3.判断Settings中没有启用锁屏 。
4.判断是否设置了密码等。
5.符合条件,显示锁屏。
private void handleSystemReady() {
synchronized (this) {
if (DEBUG) Log.d(TAG, "onSystemReady");
mSystemReady = true;
Log.d("sunyuke","启动锁屏界面处理");
doKeyguardLocked(null);
mUpdateMonitor.registerCallback(mUpdateCallback);
mPowerOffAlarmManager.onSystemReady();
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
}
private void doKeyguardLocked(Bundle options) {
...
//展示锁屏页面
showLocked(options);
}
private void handleShow(Bundle options) {
...
synchronized (KeyguardViewMediator.this) {
...
//加载锁屏页面
mStatusBarKeyguardViewManager.show(options);
...
}
...
}
跟着方法一路走下来最终会调用StatusBarKeyguardViewManager中的showBouncerOrKeyguard方法加载锁屏页面及密码解锁页面
protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
if (DEBUG) Log.d(TAG, "showBouncerOrKeyguard() is called.");
if (mBouncer.needsFullscreenBouncer() && !mDozing) {
if (DEBUG) {
Log.d(TAG, "needsFullscreenBouncer() is true, show \"Bouncer\" view directly.");
}
Log.d("sunyuke","隐藏锁屏界面,显示密码解锁界面");
// The keyguard might be showing (already). So we need to hide it.
mStatusBar.hideKeyguard();
mBouncer.show(true /* resetSecuritySelection */);
} else {
if (DEBUG) {
Log.d(TAG, "needsFullscreenBouncer() is false,"
+ "show \"Notification Keyguard\" view.");
}
Log.d("sunyuke","显示锁屏界面");
mStatusBar.showKeyguard();
if (hideBouncerWhenShowing) {
hideBouncer(shouldDestroyViewOnReset() /* destroyView */);
mBouncer.prepare();
}
}
updateStates();
}
调用KeyguardBouncer类中的needsFullscreenBouncer方法
public boolean needsFullscreenBouncer() {
ensureView();
/*if (mKeyguardView != null) {
SecurityMode mode = mKeyguardView.getSecurityMode();
return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
}
return false;*/
SecurityMode mode = mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
return mode == SecurityMode.SimPinPukMe1
|| mode == SecurityMode.SimPinPukMe2
|| mode == SecurityMode.SimPinPukMe3
|| mode == SecurityMode.SimPinPukMe4
|| mode == SecurityMode.AntiTheft
|| mode == SecurityMode.AlarmBoot;
}
protected void ensureView() {
//是否执行了移除密码view
boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
//如果锁屏密码为空或进行了删除才往下执行
if (mRoot == null || forceRemoval) {
inflateView();
}
}
protected void inflateView() {
//确保没有重复的锁屏密码页面
removeView();
mHandler.removeCallbacks(mRemoveViewRunnable);
//创建锁屏密码页面
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
// M: Add to show message for MTK FaceUnlock
mMessageView = (TextView) mRoot.findViewById(R.id.face_secure_msg);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mCallback);
mContainer.addView(mRoot, mContainer.getChildCount());
mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
com.android.systemui.R.dimen.status_bar_height);
mRoot.setVisibility(View.INVISIBLE);
mRoot.setAccessibilityPaneTitle(mKeyguardView.getAccessibilityTitleForCurrentMode());
final WindowInsets rootInsets = mRoot.getRootWindowInsets();
if (rootInsets != null) {
mRoot.dispatchApplyWindowInsets(rootInsets);
}
}
KeyguardHostView就是锁屏密码View
@Override
protected void onFinishInflate() {
Log.d("sunyuke","showPrimarySecurityScreen1");
mSecurityContainer =
findViewById(R.id.keyguard_security_container);
mLockPatternUtils = new LockPatternUtils(mContext);
mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
mSecurityContainer.setSecurityCallback(this);
mSecurityContainer.showPrimarySecurityScreen(false);
// mSecurityContainer.updateSecurityViews(false /* not bouncing */);
}
主要看showPrimarySecurityScreen方法,根据流程往下走,回执行KeyguardSecurityContainer类中的showSecurityScreen方法
/**
* 切换到给定的密码解锁页面,除非它已经被显示
* this is a no-op.
*
* @param securityMode 密码解锁类型 1.None没有锁屏密码 2. Pattern 图形密码 3.Password 普通的密码 4.PIN PIN密码
*/
private void showSecurityScreen(SecurityMode securityMode) {
if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
//判断是否加载过解锁密码页面
if ((securityMode == mCurrentSecuritySelection)
&& (securityMode != SecurityMode.AntiTheft)) {
return;
}
Log.d(TAG, "showSecurityScreen() - get oldview for" + mCurrentSecuritySelection
+ ", get newview for" + securityMode);
KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
KeyguardSecurityView newView = getSecurityView(securityMode);
// Emulate Activity life cycle
if (oldView != null) {
oldView.onPause();
oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
}
if (securityMode != SecurityMode.None) {
/// M: fix ALPS01832185,
/// KeyguardAntiTheftView needs the latest mCallback before onResume.
newView.setKeyguardCallback(mCallback);
Log.d(TAG, "showSecurityScreen() - newview.setKeyguardCallback(mCallback)");
newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
}
// Find and show this child.
final int childCount = mSecurityViewFlipper.getChildCount();
final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
for (int i = 0; i < childCount; i++) {
if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
mSecurityViewFlipper.setDisplayedChild(i);
break;
}
}
mCurrentSecuritySelection = securityMode;
Log.d(TAG, "Before update, mCurrentSecuritySelection = " + securityMode
+ "After update, mCurrentSecuritySelection = " + mCurrentSecuritySelection);
mSecurityCallback.onSecurityModeChanged(securityMode,
securityMode != SecurityMode.None && newView.needsInput());
}
这块儿有一个地方我目前还没搞明白,为什么要获取oldView,根据打印的日志来看,第二次锁屏的时候mCurrentSecuritySelection的值与securityMode值是一致的,也不会往下走,所以意义在哪里?
关于锁屏后的页面主要是NotificationPanelView类控制,我们看StatusBar类,在makeStatusBarView方法中就创建了锁屏的页面
//StatusBar
protected void makeStatusBarView() {
...
// 创建 NotificationPanelView
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
mZenController.addCallback(this);
...
//创建 KeyguardStatusBarView
mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
//NotificationPanelView
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
mNotificationContainerParent = findViewById(R.id.notification_container_parent);
mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
//填充锁屏图标的layout
mKeyguardBottomArea = findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mLastOrientation = getResources().getConfiguration().orientation;
initBottomArea();
mQsFrame = findViewById(R.id.qs_frame);
}
//KeyguardBottomArea
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
*/
public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
UnlockMethodCache.OnUnlockMethodChangedListener,
AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
...
}