Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 從 鎖屏服務AIDL線程通信案例看Android 底層啟動

從 鎖屏服務AIDL線程通信案例看Android 底層啟動

編輯:關於Android編程

從 鎖屏服務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?
  1. private void doKeyguardLocked() {
  2. doKeyguardLocked(null);
  3. }
  4.  
  5. /**
  6. * Enable the keyguard if the settings are appropriate.
  7. */
  8. private void doKeyguardLocked(Bundle options) {
  9. // if another app is disabling us, don't show
  10. if (!mExternallyEnabled || KeyguardUpdateMonitor.isAlarmBoot()) {
  11. if (DEBUG) KeyguardUtils.xlogD(TAG, doKeyguard: not showing because externally disabled);
  12.  
  13. // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes
  14. // for an occasional ugly flicker in this situation:
  15. // 1) receive a call with the screen on (no keyguard) or make a call
  16. // 2) screen times out
  17. // 3) user hits key to turn screen back on
  18. // instead, we reenable the keyguard when we know the screen is off and the call
  19. // ends (see the broadcast receiver below)
  20. // TODO: clean this up when we have better support at the window manager level
  21. // for apps that wish to be on top of the keyguard
  22. return;
  23. }
  24.  
  25. // if the keyguard is already showing, don't bother
  26. if (mKeyguardViewManager.isShowing()) {
  27. if (DEBUG) KeyguardUtils.xlogD(TAG, doKeyguard: not showing because it is already showing);
  28. return;
  29. }
  30.  
  31. // if the setup wizard hasn't run yet, don't show
  32. if (DEBUG) KeyguardUtils.xlogD(TAG, doKeyguard: get keyguard.no_require_sim property before);
  33. final boolean requireSim = !SystemProperties.getBoolean(keyguard.no_require_sim,
  34. false);
  35. if (DEBUG) KeyguardUtils.xlogD(TAG, doKeyguard: get keyguard.no_require_sim property after);
  36. final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
  37. final IccCardConstants.State state = mUpdateMonitor.getSimState();
  38. boolean lockedOrMissing = false;
  39. /// M: Support GeminiPlus
  40. for (int i = PhoneConstants.GEMINI_SIM_1; i <= KeyguardUtils.getMaxSimId(); i++) {
  41. lockedOrMissing = (lockedOrMissing || isLockedOrMissingGemini(i, requireSim));
  42. if (lockedOrMissing) {
  43. break;
  44. }
  45. }
  46.  
  47. if (DEBUG) KeyguardUtils.xlogD(TAG, doKeyguard: get sim state after);
  48.  
  49. /// M: MTK MOTA UPDATE when on ics2 keygaurd set none,update to JB,the keyguard will show LockScreen.
  50. /// MTK MOTA UPDATE when the phone first boot,check the settingDB mirged or not ,because mota update,
  51. /// the settingdb migrate slow than keygaurd(timing sequence problem) @{
  52. boolean keyguardDisable = false;
  53.  
  54. /////*************************************TODO
  55. boolean motaUpdateFirst = true;//mLockPatternUtils.isDbMigrated();
  56. if (motaUpdateFirst) {
  57. /// DB mogi done
  58. keyguardDisable = mLockPatternUtils.isLockScreenDisabled();
  59. } else {
  60. /// DB not mogi
  61. final ContentResolver cr = mContext.getContentResolver();
  62. String value = Settings.Secure.getString(cr, lockscreen.disabled);
  63. boolean booleanValue = false;
  64. if( null!=value ){
  65. booleanValue = value.equals(1) ? true :false;
  66. }
  67. keyguardDisable = (!mLockPatternUtils.isSecure()) && booleanValue;
  68. }
  69. /// @}
  70.  
  71. if (DEBUG) KeyguardUtils.xlogD(TAG, doKeyguard: keyguardDisable query end);
  72.  
  73. /// M: Add new condition DM lock is not true
  74. boolean dmLocked = KeyguardUpdateMonitor.getInstance(mContext).dmIsLocked();
  75. KeyguardUtils.xlogD(TAG, lockedOrMissing is + lockedOrMissing + , requireSim= + requireSim
  76. + , provisioned= + provisioned + , keyguardisable= + keyguardDisable + , dmLocked= + dmLocked);
  77.  
  78. if (!lockedOrMissing && !provisioned && !dmLocked) {
  79. if (DEBUG) Log.d(TAG, doKeyguard: not showing because device isn't provisioned
  80. + and the sim is not locked or missing);
  81. return;
  82. }
  83.  
  84. /// M: Add a new condition DM lock is not on, or user can still bypass dm lock when Keygaurd is disabled
  85. if (mUserManager.getUsers(true).size() < 2
  86. && keyguardDisable && !lockedOrMissing && !KeyguardUpdateMonitor.getInstance(mContext).dmIsLocked()) {
  87. if (DEBUG) Log.d(TAG, doKeyguard: not showing because lockscreen is off);
  88. return;
  89. }
  90.  
  91. if (DEBUG) Log.d(TAG, doKeyguard: showing the lock screen);
  92. showLocked(options);
  93. }

     

    來注意最後調用的這個方法showLocked(options),這個方法是啟動鎖屏關鍵的方法,來看看:

     

    [java] view plaincopyprint?
    1. /**
    2. * Send message to keyguard telling it to show itself
    3. * @see #handleShow()
    4. */
    5. private void showLocked(Bundle options) {
    6. if (DEBUG) KeyguardUtils.xlogD(TAG, showLocked);
    7. // ensure we stay awake until we are finished displaying the keyguard
    8. mShowKeyguardWakeLock.acquire();
    9. Message msg = mHandler.obtainMessage(SHOW, options);
    10. mHandler.sendMessage(msg);
    11. }

       

      這下就通過發送消息來進一步啟動鎖屏界面,來看看這個mHandler中的SHOW都做了什麼:

       

      [java] view plaincopyprint?
      1. public void handleMessage(Message msg) {
      2. if (DBG_MESSAGE) KeyguardUtils.xlogD(TAG, handleMessage enter msg name= + getMessageString(msg));
      3. switch (msg.what) {
      4. case SHOW:
      5. handleShow((Bundle) msg.obj);
      6. break; 調用的是handleShow()這個方法:

         

         

        [java] view plaincopyprint?
        1. /**
        2. * Handle message sent by {@link #showLocked}.
        3. * @see #SHOW
        4. */
        5. private void handleShow(Bundle options) {
        6. synchronized (KeyguardViewMediator.this) {
        7. if (DEBUG) KeyguardUtils.xlogD(TAG, handleShow enter);
        8. if (!mSystemReady) return;
        9. /// M: if already showing, just return
        10. if (mShowing) return;
        11.  
        12. mKeyguardViewManager.show(options);
        13.  
        14. if (DEBUG) KeyguardUtils.xlogD(TAG, handleShow mKeyguardViewManager Show exit);
        15.  
        16. mShowing = true;
        17. mKeyguardDonePending = false;
        18. updateActivityLockScreenState();
        19. adjustStatusBarLocked();
        20. userActivity();
        21. try {
        22. ActivityManagerNative.getDefault().closeSystemDialogs(lock);
        23. } catch (RemoteException e) {
        24. }
        25.  
        26. if (DEBUG) KeyguardUtils.xlogD(TAG, handleShow query AlarmBoot before);
        27. // Do this at the end to not slow down display of the keyguard.
        28. if (!KeyguardUpdateMonitor.isAlarmBoot()) {
        29. playSounds(true);
        30. } else {
        31. new Handler().postDelayed(new Runnable() {
        32. public void run() {
        33. sendRemoveIPOWinBroadcast();
        34. startAlarm();
        35. }
        36. }, 250);
        37. }
        38. mShowKeyguardWakeLock.release();
        39. if (DEBUG) KeyguardUtils.xlogD(TAG, handleShow exit);
        40. }
        41. }
          接著看mKeyguardViewManager.show(options);這個方法都干了什麼:

           

           

          [java] view plaincopyprint?
          1. /**
          2. * Show the keyguard. Will handle creating and attaching to the view manager
          3. * lazily.
          4. */
          5. public synchronized void show(Bundle options) {
          6. if (DEBUG) KeyguardUtils.xlogD(TAG, show(); mKeyguardView= + mKeyguardView);
          7.  
          8. boolean enableScreenRotation = shouldEnableScreenRotation();
          9. if (DEBUG) KeyguardUtils.xlogD(TAG, show() query screen rotation after);
          10.  
          11. /// M: Incoming Indicator for Keyguard Rotation @{
          12. KeyguardUpdateMonitor.getInstance(mContext).setQueryBaseTime();
          13. /// @}
          14. maybeCreateKeyguardLocked(enableScreenRotation, false, options);
          15.  
          16. if (DEBUG) KeyguardUtils.xlogD(TAG, show() maybeCreateKeyguardLocked finish);
          17.  
          18. maybeEnableScreenRotation(enableScreenRotation);
          19.  
          20. // Disable common aspects of the system/status/navigation bars that are not appropriate or
          21. // useful on any keyguard screen but can be re-shown by dialogs or SHOW_WHEN_LOCKED
          22. // activities. Other disabled bits are handled by the KeyguardViewMediator talking
          23. // directly to the status bar service.
          24. final int visFlags = View.STATUS_BAR_DISABLE_HOME;
          25. if (DEBUG) KeyguardUtils.xlogD(TAG, show:setSystemUiVisibility( + Integer.toHexString(visFlags)+));
          26. mKeyguardHost.setSystemUiVisibility(visFlags);
          27.  
          28. mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
          29. mKeyguardHost.setVisibility(View.VISIBLE);
          30. mKeyguardView.show();
          31. mKeyguardView.requestFocus();
          32. if (DEBUG) KeyguardUtils.xlogD(TAG, show() exit; mKeyguardView= + mKeyguardView);
          33. }

             

            這下終於看到如山真面目了,看裡面的方法maybeCreateKeyguardLocked()這個是真正起作用的地方:

             

            [java] view plaincopyprint?
            1. private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
            2. Bundle options) {
            3. final boolean isActivity = (mContext instanceof Activity); // for test activity
            4.  
            5. if (mKeyguardHost != null) {
            6. mKeyguardHost.saveHierarchyState(mStateContainer);
            7. }
            8.  
            9. if (mKeyguardHost == null) {
            10. if (DEBUG) KeyguardUtils.xlogD(TAG, keyguard host is null, creating it...);
            11.  
            12. mKeyguardHost = new ViewManagerHost(mContext);
            13.  
            14. int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
            15. | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
            16. | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
            17. | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
            18.  
            19. /// M: Modify to support DM lock, hide statusbr when dm lock power on @{
            20. KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
            21. if (monitor.dmIsLocked()) { //in the first created
            22. if (DEBUG) KeyguardUtils.xlogD(TAG, show(); dmIsLocked );
            23. flags &= ~WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
            24. flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            25. flags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
            26. } else if (KeyguardUpdateMonitor.isAlarmBoot()) {
            27. if (DEBUG) KeyguardUtils.xlogD(TAG, show(); AlarmBoot );
            28. flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            29. flags &= ~WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
            30. flags |= WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
            31. }
            32. /// M: @}
            33. if (!mNeedsInput) {
            34. flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
            35. }
            36. if (ActivityManager.isHighEndGfx()) {
            37. flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            38. }
            39.  
            40. final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
            41. final int type = isActivity ? WindowManager.LayoutParams.TYPE_APPLICATION
            42. : WindowManager.LayoutParams.TYPE_KEYGUARD;
            43. WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
            44. stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
            45. lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
            46. lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
            47. if (ActivityManager.isHighEndGfx()) {
            48. lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            49. lp.privateFlags |=
            50. WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
            51. }
            52. lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
            53. if (isActivity) {
            54. lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
            55. }
            56. /// M: Poke user activity when operating Keyguard
            57. //lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
            58. lp.setTitle(isActivity ? KeyguardMock : Keyguard);
            59. mWindowLayoutParams = lp;
            60. mViewManager.addView(mKeyguardHost, lp);
            61. }
            62.  
            63. /// M: If force and keyguardView is not null, we should relase memory hold by old keyguardview
            64. if (force && mKeyguardView != null) {
            65. mKeyguardView.cleanUp();
            66. }
            67.  
            68. if (force || mKeyguardView == null) {
            69. inflateKeyguardView(options);
            70. mKeyguardView.requestFocus();
            71. }
            72. updateUserActivityTimeoutInWindowLayoutParams();
            73. mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
            74.  
            75. mKeyguardHost.restoreHierarchyState(mStateContainer);
            76. } 這下通過 mViewManager.addView(mKeyguardHost, lp);這個方法真正地把鎖屏界面添加到屏幕上,其實這個就是個view,擋在了手機的屏幕的最上方。而這個mKeyguardHost就是鎖屏的根。而第一次加載的時候mKeyguardView為空,調用inflateKeyguardView(),初始化鎖屏的view。

               

               

              來看看這個inflateKeyguardView()這個方法都加載了哪個布局:

               

              [java] view plaincopyprint?
              1. private void inflateKeyguardView(Bundle options) {
              2. /// M: add for power-off alarm @{
              3. int resId = R.id.keyguard_host_view;
              4. int layoutId = R.layout.keyguard_host_view;
              5. if(KeyguardUpdateMonitor.isAlarmBoot()){
              6. layoutId = com.mediatek.internal.R.layout.power_off_alarm_host_view;
              7. resId = com.mediatek.internal.R.id.keyguard_host_view;
              8. }
              9. /// @}
              10. View v = mKeyguardHost.findViewById(resId);
              11. if (v != null) {
              12. mKeyguardHost.removeView(v);
              13. }
              14. // TODO: Remove once b/7094175 is fixed
              15. if (false) Slog.d(TAG, inflateKeyguardView: b/7094175 mContext.config=
              16. + mContext.getResources().getConfiguration());
              17.  
              18. /// M: Save new orientation
              19. mCreateOrientation = mContext.getResources().getConfiguration().orientation;
              20.  
              21. final LayoutInflater inflater = LayoutInflater.from(mContext);
              22. View view = inflater.inflate(layoutId, mKeyguardHost, true);
              23. mKeyguardView = (KeyguardHostView) view.findViewById(resId);
              24. mKeyguardView.setLockPatternUtils(mLockPatternUtils);
              25. mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
              26.  
              27. // HACK
              28. // The keyguard view will have set up window flags in onFinishInflate before we set
              29. // the view mediator callback. Make sure it knows the correct IME state.
              30. if (mViewMediatorCallback != null) {
              31. KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
              32. R.id.keyguard_password_view);
              33.  
              34. if (kpv != null) {
              35. mViewMediatorCallback.setNeedsInput(kpv.needsInput());
              36. }
              37. }
              38.  
              39. /// Extract this block to a single function
              40. updateKeyguardViewFromOptions(options);
              41. } 這個加載了keyguard_host_view這個layout,來看看這個布局是怎麼寫的:

                 

                 

                [html] view plaincopyprint?
                1. xmlns:android=http://schemas.android.com/apk/res/android
                2. xmlns:androidprv=http://schemas.android.com/apk/res/android
                3. android:id=@+id/keyguard_host_view
                4. android:layout_width=match_parent
                5. android:layout_height=match_parent
                6. android:gravity=center_horizontal
                7. android:orientation=vertical>
                8.  
                9. android:id=@+id/sliding_layout
                10. android:layout_width=match_parent
                11. android:layout_height=match_parent>
                12.  
                13. <framelayout li=""> android:layout_width=match_parent </framelayout>
                14. android:layout_height=match_parent
                15. androidprv:layout_childType=mediatekLayerBackground>
                16.  
                17.  
                18. <framelayout li=""> android:layout_width=match_parent </framelayout>
                19. android:layout_height=wrap_content
                20. androidprv:layout_childType=pageDeleteDropTarget>
                21. android:id=@+id/keyguard_widget_pager_delete_target
                22. android:layout_width=wrap_content
                23. android:layout_height=wrap_content
                24. android:layout_gravity=top|center_horizontal />
                25.  
                26.  
                27. <framelayout class="alt" li=""> android:layout_width=match_parent </framelayout>
                28. android:layout_height=match_parent
                29. androidprv:layout_childType=widgets>
                30. android:id=@+id/app_widget_container
                31. android:layout_width=match_parent
                32. android:layout_height=match_parent
                33. android:layout_gravity=center/>
                34.  
                35.  
                36. android:layout_height=match_parent
                37. androidprv:layout_childType=scrim
                38. android:background=#99000000 />
                39.  
                40. <framelayout class="alt" li=""> android:layout_width=match_parent </framelayout>
                41. android:layout_height=match_parent
                42. androidprv:layout_childType=mediatekLayerForeground>
                43.  
                44.  
                45. android:id=@+id/keyguard_security_container
                46. android:layout_width=wrap_content
                47. android:layout_height=wrap_content
                48. android:layout_maxHeight=@dimen/keyguard_security_height
                49. androidprv:layout_childType=challenge
                50. android:padding=0dp
                51. android:gravity=bottom|center_horizontal>
                52. android:id=@+id/view_flipper
                53. android:layout_width=match_parent
                54. android:layout_height=match_parent
                55. android:clipToPadding=false
                56. android:paddingTop=@dimen/keyguard_security_view_margin
                57. android:gravity=center>
                58.  
                59.  
                60.  
                61. android:layout_width=match_parent
                62. android:layout_height=@dimen/kg_widget_pager_bottom_padding
                63. androidprv:layout_childType=expandChallengeHandle
                64. android:focusable=true
                65. android:background=@null
                66. android:src=@drawable/keyguard_expand_challenge_handle
                67. android:scaleType=center
                68. android:contentDescription=@string/keyguard_accessibility_expand_lock_area />
                69.  
                70.  
                71. 而這個KeyguardHostView.java就是鎖屏的真正的處理的view,該添加什麼樣的鎖屏,例如:PIN,Pattern,PUK,Password等等,都是由它來控制的,最後會調用到getLayoutIdFor()這個方法,來啟動那種鎖屏界面,如下:

                   

                   

                  [java] view plaincopyprint?
                  1. private int getLayoutIdFor(SecurityMode securityMode) {
                  2. switch (securityMode) {
                  3. case None: return R.layout.keyguard_selector_view;
                  4. case Pattern: return R.layout.keyguard_pattern_view;
                  5. case PIN: return R.layout.keyguard_pin_view;
                  6. case Password: return R.layout.keyguard_password_view;
                  7. case Biometric: return R.layout.keyguard_face_unlock_view;
                  8. case Account: return R.layout.keyguard_account_view;
                  9. /// M: Modify Sim unlock layout @{
                  10. //case SimPin: return R.layout.keyguard_sim_pin_view;
                  11. //case SimPuk: return R.layout.keyguard_sim_puk_view;
                  12. case SimPinPukMe1: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view;
                  13. case SimPinPukMe2: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view;
                  14. /// M: Support GeminiPlus
                  15. case SimPinPukMe3: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view;
                  16. case SimPinPukMe4: return com.mediatek.internal.R.layout.keyguard_sim_pin_puk_view;
                  17. /// @}
                  18.  
                  19. /// M: power-off alarm @{
                  20. case AlarmBoot: return com.mediatek.internal.R.layout.power_off_alarm_view;
                  21. /// @}
                  22. ///M: add voice unlock view layout
                  23. case Voice: return R.layout.zz_keyguard_voice_unlock_view;
                  24. default:
                  25. return 0;
                  26. }
                  27. } 到這,鎖屏已經初始化完了,要想下面接著分析,估計大家應該都能分析過去了;

                     

                     

                    特別說明

                    1、加載鎖屏widget的地方在KeyguardHostView.java的onFinishInflate()中,調用的addDefaultWidget()這個方法中添加了單click事件,最後調用到KeyguardActivityLauncher.java的launcherWidgetPicker()這個方法;

                    2、要想你寫的widget能被鎖屏widget過濾出來,只需要在wdget的xml中添加一個屬性即可:

                    android:widgetCategory=home_screen|keyguard,這樣你寫的桌面widget,也能在鎖屏wiget過濾出來,具體布局需要你微調下;

                     

                    添加一張圖,

                     

                    \

                     

                     

                    到了這一步,我們的整個鎖屏框架就已經很明顯了

                    特別感謝

                     

                     

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved