android4.4的Keyguard心得

來源:互聯網
上載者:User

標籤:android   keyguard   

在總結鎖屏代碼之前,有兩個中心思想要銘記於心

A) KeyguardHostView就是我們最終所要展示的介面,所以不論用什麼方法手段,都要將這個KeyguardHostView添加到視窗中,後續填充它,都是細節問題

B) 那麼問題來了,通常我們將一個view添加到視窗中會用什麼方法呢?

        答案有兩種 1 WindowManager.addView()  2 LayoutInflater.inflate(resID, parentView, true); 而在鎖屏代碼中這兩種方法都有用到

-----------------------------------------------華麗麗的分割線-------------------------------------------------------------------

接下來用一張圖來解釋流程



-------------------------------又是可愛的分割線--------------------------------------------------------

可以看到, 開機後首先從PhoneWindowManager的systemReady方法調用兩個封裝類(KeyguardServiceDelegate.java  KeyguardServiceWrapper.java)之後會調用到KeyguardService.java中的onSystemReady,進而調用鎖屏代碼的總調度使KeyguardViewMediator.java。它就是鎖屏的CEO。做我們軟體的都知道,CEO一般不會太牽涉代碼問題,只管分配,協調工作,客戶/供應鏈的溝通。在KeyguardViewMediator.java中的mExternallyEnabled變數就是總監與客戶談判的籌碼,如果客戶第三方通過KeyguardManager.diableKeyguard()方法禁用系統鎖屏後,此變數會置為false,從而不會繪製系統鎖定畫面,otherwise,將任務大手一甩直接丟給總經理KeyguardViewManager.java.具體代碼如下:

<span style="font-size:12px;">    /**     * Enable the keyguard if the settings are appropriate.     */    private void doKeyguardLocked(Bundle options) {        boolean isSimSecure = mUpdateMonitor.isSimPinSecure();        ///M: if another app is disabling us (except Sim Secure), then don't show        if ((!mExternallyEnabled && !isSimSecure)|| PowerOffAlarmManager.isAlarmBoot()) {        if (DEBUG) KeyguardUtils.xlogD(TAG, "doKeyguard: not showing because externally disabled");            return;        }        。。。        showLocked(options);    }    private void handleShow(Bundle options) {        。。。        mKeyguardViewManager.show(options);        。。。    }通過以上代碼,所有的任務都已經落實到KeyguardViewManager.java的頭上,接下來看看這個總經理是如何工作的 /**     * 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 = KeyguardUtils.shouldEnableScreenRotation(mContext);        if (DEBUG) Log.d(TAG, "show() query screen rotation after");        /// M: Incoming Indicator for Keyguard Rotation @{        KeyguardUpdateMonitor.getInstance(mContext).setQueryBaseTime();        /// @}        <span style="color:#FF0000;">maybeCreateKeyguardLocked(enableScreenRotation, false, options);</span>                if (DEBUG) Log.d(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.        int visFlags = View.STATUS_BAR_DISABLE_HOME;        if (shouldEnableTranslucentDecor()) {            mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS                                       | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;        }        if (DEBUG) Log.d(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")");        mKeyguardHost.setSystemUiVisibility(visFlags);        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);        mKeyguardHost.setVisibility(View.VISIBLE);        <span style="color:#FF0000;">mKeyguardView.show();</span>        mKeyguardView.requestFocus();        if (DEBUG) Log.d(TAG, "show() exit; mKeyguardView=" + mKeyguardView);    }關鍵代碼所以全部貼出來分析分析吧, <span style="color:#009900;">//有一點需要提前注意mKeyguardHost只是一個空View,mKeyguardView才是真正的KeyguardHostView</span>boolean enableScreenRotation用來判斷是否允許旋轉螢幕,KeyguardUpdateMonitor.getInstance(mContext).setQueryBaseTime();此行代碼是為了重新設定query的時間,比如未接來電,未讀簡訊等,之所以重新set是為了仿照iphone手機,繪製鎖屏時,查詢未讀資訊/未接電話的數目是針對本次鎖屏後收到的未讀資訊/未接電話
maybeCreateKeyguardLocked(enableScreenRotation, false, options); 我擦~終於到關鍵代碼了,此方法就是真正建立鎖屏的方法,來一睹芳容吧    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...");            <span style="color:#990000;">mKeyguardHost = new ViewManagerHost(mContext);</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;            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;            /// M: Poke user activity when operating Keyguard            //lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;            lp.setTitle("Keyguard");            mWindowLayoutParams = lp;            ///M: skip add KeyguardHost into viewManager in AT case            if (!KeyguardViewMediator.isKeyguardInActivity) {                <span style="color:#CC0000;">mViewManager.addView(mKeyguardHost, lp);</span>            } else {                if (DEBUG) Log.d(TAG, "skip add mKeyguardHost into mViewManager for testing");            }            KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mBackgroundChanger);        }       /// 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) {                mKeyguardHost.setCustomBackground(null);                mKeyguardHost.removeAllViews();                <span style="color:#CC0000;">inflateKeyguardView(options);</span>                mKeyguardView.requestFocus();        }        updateUserActivityTimeoutInWindowLayoutParams();        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);        mKeyguardHost.restoreHierarchyState(mStateContainer);    }
此處紅色代碼中通過mViewManager.addView(mKeyguardHost, lp);將初始話的mKeyguardHost(空view)通過WindowManager.addView的方式添加到視窗之中
然後在通過inflateKeyguardView(options);方法將真正的KeyguardHostView也添加到mKeyguardHost中, 具體如何添加請看代碼:

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(PowerOffAlarmManager.isAlarmBoot()){
            resId = R.id.power_off_alarm_host_view;
            layoutId = R.layout.mtk_power_off_alarm_host_view;
        }
        /// @}
        View v = mKeyguardHost.findViewById(resId);
        if (v != null) {
            mKeyguardHost.removeView(v);
        }
        /// M: Save new orientation
        mCreateOrientation = mContext.getResources().getConfiguration().orientation;
        mCreateScreenWidthDp = mContext.getResources().getConfiguration().screenWidthDp;
        mCreateScreenHeightDp = mContext.getResources().getConfiguration().screenHeightDp;
        
        final LayoutInflater inflater = LayoutInflater.from(mContext);
        View view = inflater.inflate(layoutId, mKeyguardHost, true);
        mKeyguardView = (KeyguardHostView) view.findViewById(resId);
        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
        mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
        mKeyguardView.initializeSwitchingUserState(options != null &&
                options.getBoolean(IS_SWITCHING_USER));
        
        // 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) {
            // Start of cube26 code
            if (mLockscreenNotifications)
                mNotificationView.setViewMediator(mViewMediatorCallback);
            // End of cube26 code
            
            KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
                    R.id.keyguard_password_view);

            if (kpv != null) {
                mViewMediatorCallback.setNeedsInput(kpv.needsInput());
            }
        }

        if (options != null) {
            int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
            if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
                mKeyguardView.goToWidget(widgetToShow);
            }
        }
    }
紅色標記處,通過LayoutInflater.inflate(resId, parentView, true)的方式將R.layout.keyguard_host_view添加到mKeyguardHost這個空view中
自此真正的KeyguardHostView已經添加到視窗中,並且通過各中layoutparam將其顯示在最上層,後續的就是如何將其顯示,使用何種方式顯示,比如Slide,Swipe,Password
等等,這些都是細節,後續部落格中將繼續分析




android4.4的Keyguard心得

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.