最近在研究将第三方锁屏内置到android系统的问题,现在有时间来梳理下最近的工作;
跟踪这个方法,就会发现它返回的是一个PhoneWindowManager对象,而
PhoneWindowManager正是实现了WindowManagerPolicy接口;那么就会进入到
PhoneWindowManager的systemReady()方法中了;
这个 KeyguardServiceDelegate做什么的呢?进入它的构造方法中看看;
首先它会去bind一个Service,这个Service的包名。类名分别是:
获取到这个Service代理对象之后,就可以和Keyguard进行交互动作了;那么真正第一次的交互应该就是 KeyguardServiceDelegate的mKeyguardConnection.onServiceConnected这个方法这里了:
进入Keyguard App之前,首先了解下几个类:
下面就是具体的调用到Keyguard App的所有方法了;
相应的,
首先我们跟踪onSystemReady()方法,对其它调用无视,看最重要的一句,doKeyguardLocked(null);中间简单调用略过,它会来到:
进入到下面这个方法以后,进入到KeyguardViewManager中,就是具体的View的操作了;
通过方法中的注释了解了具体的每一个调用的方法的作用;其中有个重要的对象就是ViewManagerHost,它代表的是整个锁屏的View,控制它就等于控制这个锁屏;
至此,我也不往下再继续深究了,网络上也有不少资料,我这篇只起一个抛砖引玉的作用吧。附一张简单的View布局;
首先列举下当前的外部条件:
1、基于CM修改的android4.2,4.4进行内置,这里以android4.4来讲解;
2、第三方锁屏是一个单独的apk,不对rom厂商进行源码开放,rom厂商源码也不对我们进行开放;
3、第三方锁屏使用了GLSurfaceView作为显示。!!!!
现在来具体的记录下各个细节;
以我们的当前的情况,首先我们要进行调试编码,必须要有一套可用的源码,而rom厂商是不会给你源码的(LOL),所以就只能自己想办法了;
首先我想到的自然是CM了,接下来就是拿取相应版本的CM android源码了,从百度百科摘录了一段,来说明CM和Android之间的版本对应关系:
CM8(Android 3.X【因为Google并没有开放这一代系统的源代码,所以跳过了开发】)
后续版本,敬请期待......
根据上面我说的条件一,我拿取CM10.1的源码,具体我就不多说了,可以参考老罗的博客:
http://blog.csdn.net/luoshengyang/article/details/29688041 ;
具体CM支持哪些机器,可以查看:
http://download.cyanogenmod.org/;
拿到了CM10.1对应机器源码并进行编译后,就可以进行后续工作了;
要想内置锁屏,首先得大体的了解系统的锁屏;所有我就首先来看看系统锁屏的加载过程;
首先,在开机时,SystemServer的initAndLoop方法中会通知WindowManagerService我系统已经Ready了,
SystemServer.java
try {
wm.systemReady();
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
WindowManagerService.java
public void systemReady() {
mPolicy.systemReady();
}
而这个mPolicy对象是在
WindowManagerService初始化的时初始化的,
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
@Override
public void systemReady() {
if (!mHeadless) {
mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
mKeyguardDelegate.onSystemReady();
}
mEdgeGestureManager = EdgeGestureManager.getInstance();
mEdgeGestureManager.setEdgeGestureActivationListener(mEdgeGestureActivationListener);
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
mHandler.post(new Runnable() {
@Override
public void run() {
updateSettings();
}
});
}
}
这个 KeyguardServiceDelegate做什么的呢?进入它的构造方法中看看;
public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
final String keyguardPackage = context.getString(
com.android.internal.R.string.config_keyguardPackage);
final String keyguardClass = context.getString(
com.android.internal.R.string.config_keyguardService);
Intent intent = new Intent();
intent.setClassName(keyguardPackage, keyguardClass);
mScrim = createScrim(context);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + keyguardClass);
} 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!)");
mKeyguardService = new KeyguardServiceWrapper(
IKeyguardService.Stub.asInterface(service));
if (mKeyguardState.systemIsReady) {
// If the system is ready, it means keyguard crashed and restarted.
mKeyguardService.onSystemReady();
// This is used to hide the scrim once keyguard displays.
mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null));
}
if (mKeyguardState.bootCompleted) {
mKeyguardService.onBootCompleted();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
mKeyguardService = null;
}
};
首先它会去bind一个Service,这个Service的包名。类名分别是:
<string name="config_keyguardPackage">com.android.keyguard</string>
<string name="config_keyguardService">com.android.keyguard.KeyguardService</string>
下面在ServiceConnection中,可以看到其获取了这个Service代理对象,叫KeyguardServiceWrapper,这个Service就是IKeyguardService,它是在
framework/base/core/java/android/internal/policy下;并且定义了一个IKeyguardService.aidl来放出接口,它的具体实现是在真正的Keyguard App中,framework/base/packages/Keyguard
mKeyguardService = new KeyguardServiceWrapper(
IKeyguardService.Stub.asInterface(service));
获取到这个Service代理对象之后,就可以和Keyguard进行交互动作了;那么真正第一次的交互应该就是 KeyguardServiceDelegate的mKeyguardConnection.onServiceConnected这个方法这里了:
if (mKeyguardState.systemIsReady) {
// If the system is ready, it means keyguard crashed and restarted.
// This is used to hide the scrim once keyguard displays.
mKeyguardService.onSystemReady();
mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null));
}
if (mKeyguardState.bootCompleted) {
mKeyguardService.onBootCompleted();
}
KeyguardViewMediator:用于控制锁屏的动作逻辑,上与PhoneWindowManager交互,下与KeyguardViewManager交互;
KeyguardViewManager:具体的锁屏View动作;
LockPatternUtils:与加密相关的工具类;
LockPatternUtils:与加密相关的工具类;
下面进入到KeyguardService中了;在KeyguardService的onCreate方法中初始化了;
@Override
public void onCreate() {
if (mKeyguardViewMediator == null) {
mKeyguardViewMediator = new KeyguardViewMediator(
KeyguardService.this, new LockPatternUtils(KeyguardService.this));
}
Log.v(TAG, "onCreate()");
}
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
public boolean isShowing() {
return mKeyguardViewMediator.isShowing();
}
public boolean isSecure() {
return mKeyguardViewMediator.isSecure();
}
public boolean isShowingAndNotHidden() {
return mKeyguardViewMediator.isShowingAndNotHidden();
}
public boolean isInputRestricted() {
return mKeyguardViewMediator.isInputRestricted();
}
public void verifyUnlock(IKeyguardExitCallback callback) {
mKeyguardViewMediator.verifyUnlock(callback);
}
public void keyguardDone(boolean authenticated, boolean wakeup) {
checkPermission();
mKeyguardViewMediator.keyguardDone(authenticated, wakeup);
}
public void setHidden(boolean isHidden) {
checkPermission();
mKeyguardViewMediator.setHidden(isHidden);
}
public void dismiss() {
mKeyguardViewMediator.dismiss();
}
public void onDreamingStarted() {
checkPermission();
mKeyguardViewMediator.onDreamingStarted();
}
public void onDreamingStopped() {
checkPermission();
mKeyguardViewMediator.onDreamingStopped();
}
public void onScreenTurnedOff(int reason) {
checkPermission();
mKeyguardViewMediator.onScreenTurnedOff(reason);
}
public void onScreenTurnedOn(IKeyguardShowCallback callback) {
checkPermission();
mKeyguardViewMediator.onScreenTurnedOn(callback);
}
public void setKeyguardEnabled(boolean enabled) {
checkPermission();
mKeyguardViewMediator.setKeyguardEnabled(enabled);
}
public boolean isDismissable() {
return mKeyguardViewMediator.isDismissable();
}
public void onSystemReady() {
checkPermission();
mKeyguardViewMediator.onSystemReady();
}
public void doKeyguardTimeout(Bundle options) {
checkPermission();
mKeyguardViewMediator.doKeyguardTimeout(options);
}
public void setCurrentUser(int userId) {
checkPermission();
mKeyguardViewMediator.setCurrentUser(userId);
}
public void showAssistant() {
checkPermission();
mKeyguardViewMediator.showAssistant();
}
public void dispatch(MotionEvent event) {
checkPermission();
mKeyguardViewMediator.dispatch(event);
}
public void launchCamera() {
checkPermission();
mKeyguardViewMediator.launchCamera();
}
public void onBootCompleted() {
checkPermission();
mKeyguardViewMediator.onBootCompleted();
}
};
mKeyguardService.onSystemReady();
告诉Keyguard App系统已经Ready,你要显示锁屏了;
/**
* 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()) {
if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
mUpdateMonitor.setAlternateUnlockEnabled(false);
} else {
mUpdateMonitor.setAlternateUnlockEnabled(true);
}
doKeyguardLocked(null); //显示锁屏View
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
}
相应的,
mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null));
告诉keyguard App屏幕点亮;
/**
* Let's us know the screen was turned on.
*/
public void onScreenTurnedOn(IKeyguardShowCallback callback) {
synchronized (this) {
mScreenOn = true;
cancelDoKeyguardLaterLocked();
if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
if (callback != null) {
notifyScreenOnLocked(callback);
}
}
KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurnedOn();
maybeSendUserPresentBroadcast();
}
首先我们跟踪onSystemReady()方法,对其它调用无视,看最重要的一句,doKeyguardLocked(null);中间简单调用略过,它会来到:
/**
* Handle message sent by {@link #showLocked}.
* @see #SHOW
*/
private void handleShow(Bundle options) {
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
return;
} else {
if (DEBUG) Log.d(TAG, "handleShow");
}
new Thread(new Runnable() {
public void run() {
playSounds(true); <span style="font-family: 微软雅黑;">//播放锁屏声音</span>
}
}).start();
mKeyguardViewManager.show(options); //大头,锁屏显示
mShowing = true;
mKeyguardDonePending = false;
updateActivityLockScreenState();//告诉ActivityManagerService当前锁屏是showing还是hidden;
adjustStatusBarLocked(); //控制StatusBar的状态,下拉或者不能下拉
userActivity(); //告诉PowerManager当前有用户操作
try {
ActivityManagerNative.getDefault().closeSystemDialogs("lock");//关闭系统dialog????
} catch (RemoteException e) {
}
mShowKeyguardWakeLock.release();
}
mKeyguardDisplayManager.show(); //无视
}
进入到下面这个方法以后,进入到KeyguardViewManager中,就是具体的View的操作了;
mKeyguardViewManager.show(options);
/**
* 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 = shouldEnableScreenRotation(); //锁屏下的横竖屏
maybeCreateKeyguardLocked(enableScreenRotation, false, options); //大头,创建锁屏View
maybeEnableScreenRotation(enableScreenRotation); <span style="font-family: 微软雅黑;">//锁屏下的横竖屏</span>
updateShowWallpaper(mKeyguardHost.shouldShowWallpaper()); //WALLPAPER显示
// 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()) { //控制状态栏和navigation bar的透明
mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
}
if (DEBUG) Log.v(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")");
mKeyguardHost.setSystemUiVisibility(visFlags);
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.setVisibility(View.VISIBLE);
mKeyguardView.show(); //显示密码View,各种不同的加密view
mKeyguardView.requestFocus();
}
通过方法中的注释了解了具体的每一个调用的方法的作用;其中有个重要的对象就是ViewManagerHost,它代表的是整个锁屏的View,控制它就等于控制这个锁屏;
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...");
mKeyguardHost = new ViewManagerHost(mContext); //初始化<span style="font-family: 微软雅黑;">ViewManagerHost</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
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
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;
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
lp.setTitle("Keyguard");
mWindowLayoutParams = lp;
mViewManager.addView(mKeyguardHost, lp); //将这个根View添加到WindowManager
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mBackgroundChanger);
mKeyguardHost.postDelayed(new Runnable() {
@Override
public void run() {
mKeyguardHost.cacheUserImage();
}
}, 100);
}
if (force || mKeyguardView == null) {
mKeyguardHost.setCustomBackground(null);
mKeyguardHost.removeAllViews();
inflateKeyguardView(options); //加载具体的View layout
mKeyguardView.requestFocus();
}
updateUserActivityTimeoutInWindowLayoutParams();
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.restoreHierarchyState(mStateContainer);
}
至此,我也不往下再继续深究了,网络上也有不少资料,我这篇只起一个抛砖引玉的作用吧。附一张简单的View布局;