從 鎖屏服務AIDL線程通信案例看Android 底層啟動
請確保 你已經閱讀過 我的 Android Window、PhoneWindow、WindowManager、Activity學習心得 第一彈 系列和
Android init啟動和Zygote服務
Android啟動續-------SystemSever啟動
Android AIDL理解
7篇文章,並且初步理解其核心內容 此處,我們從SystemSever的啟動開始說起 目錄/android/4.4/frameworks/base/services/java/com/android/server/SystemServer.java
開始繼續說起
wm = WindowManagerService.main(context, power, display, inputManager,
wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
try { wm.systemReady(); } catch (Throwable e) { reportWtf(making Window Manager Service ready, e); }
在這裡我們初始化了WindowManagerService 目錄(Android4.4/frameworks/base/services/java/com/android/server/wm/WindowManagerService.java)
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
......
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
......
public static WindowManagerService main(final Context context,
final PowerManagerService pm, final DisplayManagerService dm,
final InputManagerService im, final Handler wmHandler,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
wmHandler.runWithScissors(new Runnable() {
@Override
public void run() {
holder[0] = new WindowManagerService(context, pm, dm, im,
haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
return holder[0];
}
.......
private WindowManagerService(Context context, PowerManagerService pm,
DisplayManagerService displayManager, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
}
}
這裡,我們清楚的看到WindowManagerService也是用AIDL來實現,但是我們這裡先不管它 我們先關心
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
public void systemReady() {
mPolicy.systemReady();
}
如果說你還不理解我們的mPolicy 是什麼,你可以在返回去看看 Android Window、PhoneWindow、WindowManager、Activity學習心得 第一彈 系列
這裡,我不做出過多解釋。 我們只需要知道mPolicy 最終指向了我們PhoneWindowManager 目錄(Android4.4/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java)
public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void systemReady() {
if (!mHeadless) {
mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
mKeyguardDelegate.onSystemReady();
}
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
mHandler.post(new Runnable() {
@Override
public void run() {
updateSettings();
}
});
}
}
}
啟動到了這一步,不用我說,大家都明白是時候初始化KeyguardServiceDelegate並且告訴鎖屏的管理者,我准備好了,該你來控制加載鎖屏界面了。接著調用到了KeyguardServiceDelegate.java這個類的onSystemReady()方法
/**
* A local class that keeps a cache of keyguard state that can be restored in the event
* keyguard crashes. It currently also allows runtime-selectable
* local or remote instances of keyguard.
*/
public class KeyguardServiceDelegate {
public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
Intent intent = new Intent();
intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
mScrim = createScrim(context);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
if (DEBUG) Log.v(TAG, *** Keyguard: can't bind to + KEYGUARD_CLASS);
} 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;
}
};
public void onSystemReady() {
if (mKeyguardService != null) {
mKeyguardService.onSystemReady();
} else {
if (DEBUG) Log.v(TAG, onSystemReady() called before keyguard service was ready);
mKeyguardState.systemIsReady = true;
}
}
public void onSystemReady() {
if (mKeyguardService != null) {
mKeyguardService.onSystemReady();
} else {
if (DEBUG) Log.v(TAG, onSystemReady() called before keyguard service was ready);
mKeyguardState.systemIsReady = true;
}
}
}
到了這裡我們基本一目了然我們的KeyguardViewMediator充當了Android AIDL理解中主程的角色 同樣 毫無疑問,我們的注意力再次集中到
mKeyguardService = new KeyguardServiceWrapper(
IKeyguardService.Stub.asInterface(service));
在Android4.4/frameworks/base/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java中
public class KeyguardServiceWrapper implements IKeyguardService {
public KeyguardServiceWrapper(IKeyguardService service) {
mService = service;
}
}
這樣一來,我們的實現自然就轉移到了 Android4.4/frameworksasepackagesKeyguardsrccomandroidkeyguard/KeyguardService.java 中
public class KeyguardService extends Service {
static final String TAG = KeyguardService;
static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
private KeyguardViewMediator mKeyguardViewMediator;
@Override
public void onCreate() {
if (mKeyguardViewMediator == null) {
mKeyguardViewMediator = new KeyguardViewMediator(
KeyguardService.this, new LockPatternUtils(KeyguardService.this));
}
Log.v(TAG, onCreate());
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
// TODO
}
void checkPermission() {
if (getBaseContext().checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
Log.w(TAG, Caller needs permission ' + PERMISSION + ' to call + Debug.getCaller());
throw new SecurityException(Access denied to process: + Binder.getCallingPid()
+ , must have permission + PERMISSION);
}
}
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();
}
};
}
那麼再來看一下我們的 Android4.4/frameworksasecorejavacomandroidinternalpolicy/IKeyguardService.aidl
interface IKeyguardService {
boolean isShowing();
boolean isSecure();
boolean isShowingAndNotHidden();
boolean isInputRestricted();
boolean isDismissable();
oneway void verifyUnlock(IKeyguardExitCallback callback);
oneway void keyguardDone(boolean authenticated, boolean wakeup);
oneway void setHidden(boolean isHidden);
oneway void dismiss();
oneway void onDreamingStarted();
oneway void onDreamingStopped();
oneway void onScreenTurnedOff(int reason);
void onScreenTurnedOn(IKeyguardShowCallback callback);
oneway void setKeyguardEnabled(boolean enabled);
oneway void onSystemReady();
oneway void doKeyguardTimeout(in Bundle options);
oneway void setCurrentUser(int userId);
oneway void showAssistant();
oneway void dispatch(in MotionEvent event);
oneway void launchCamera();
oneway void onBootCompleted();
}
那麼我們的AIDL框架自然就自動布好 也就是說最終的時間處理交給了我們的 Android4.4/frameworksasepackagesKeyguardsrccomandroidkeyguard/KeyguardViewMediator.java
/**
* 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();
}
接著由doKeyguardLocked()這個方法來做啟動鎖屏界面的預處理,來看看這個方法都做了什麼:
[java] view plaincopyprint?
- 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);
- }
來注意最後調用的這個方法showLocked(options),這個方法是啟動鎖屏關鍵的方法,來看看:
[java] view plaincopyprint?
- /**
- * 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);
- }
這下就通過發送消息來進一步啟動鎖屏界面,來看看這個mHandler中的SHOW都做了什麼:
[java] view plaincopyprint?
- 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()這個方法:
[java] view plaincopyprint?
- /**
- * 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);
- }
- }
接著看mKeyguardViewManager.show(options);這個方法都干了什麼:
[java] view plaincopyprint?
- /**
- * 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);
- }
這下終於看到如山真面目了,看裡面的方法maybeCreateKeyguardLocked()這個是真正起作用的地方:
[java] view plaincopyprint?
- 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。
來看看這個inflateKeyguardView()這個方法都加載了哪個布局:
[java] view plaincopyprint?
- 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,來看看這個布局是怎麼寫的:
[html] view plaincopyprint?
- 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>
-
- android:id=@+id/sliding_layout
- android:layout_width=match_parent
- android:layout_height=match_parent>
-
- <framelayout li=""> android:layout_width=match_parent </framelayout>
- android:layout_height=match_parent
- androidprv:layout_childType=mediatekLayerBackground>
-
-
- <framelayout li=""> android:layout_width=match_parent </framelayout>
- android:layout_height=wrap_content
- androidprv:layout_childType=pageDeleteDropTarget>
- 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 class="alt" li=""> android:layout_width=match_parent </framelayout>
- android:layout_height=match_parent
- androidprv:layout_childType=widgets>
- android:id=@+id/app_widget_container
- android:layout_width=match_parent
- android:layout_height=match_parent
- android:layout_gravity=center/>
-
-
- android:layout_height=match_parent
- androidprv:layout_childType=scrim
- android:background=#99000000 />
-
- <framelayout class="alt" li=""> android:layout_width=match_parent </framelayout>
- android:layout_height=match_parent
- androidprv:layout_childType=mediatekLayerForeground>
-
-
- 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>
- 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>
-
-
-
- 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 />
-
-
- 而這個KeyguardHostView.java就是鎖屏的真正的處理的view,該添加什麼樣的鎖屏,例如:PIN,Pattern,PUK,Password等等,都是由它來控制的,最後會調用到getLayoutIdFor()這個方法,來啟動那種鎖屏界面,如下:
[java] view plaincopyprint?
- 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過濾出來,具體布局需要你微調下;
添加一張圖,
到了這一步,我們的整個鎖屏框架就已經很明顯了
特別感謝