安卓手機來電亮屏流程分析


來電亮屏流程分析

本文檔是針對手機來電時候自主點亮屏幕這一流程的分析,非常自然的就將其分為2個階段,第一個是來電,第二個是點亮屏幕。

來電的流程:

來電消息是從RIL層接收到的。然后才開始傳遞上來。

AT      : RING                             

AT      : AT< RING                            

AT      : RIL_URC_READER:RING                 

AT      : RIL_URC_READER Enter processLine    

use-Rlog/RLOG-RIL: Nw URC:RING                

use-Rlog/RLOG-RIL: receiving RING!!!!!!       

use-Rlog/RLOG-RIL: receiving first RING!!!!!! 

use-Rlog/RLOG-RIL: sending ECPI!!!!!!  

 同一時候也向RIL.java上報UNSOL_RESPONSE_CALL_STATE_CHANGED消息,RIL.java收到將才標志轉換為RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,這告訴我們真正處理代碼在哪個分支里,看以下代碼:  

processUnsolicited (Parcel p) {//主動上報的命令  

…省略代碼……  

case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:  

mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null);

break; 

}

上面這個通知發到GsmCallTracker.java文件里的構造函數中。在這里面就能看到要找的事件(EVENT_CALL_STATE_CHANGE)了:

 GsmCallTracker (GSMPhone phone) {

    this.phone = phone;

    cm = phone.mCM;

    cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);

    cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);

    cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);

在文件BaseCommands.java中有對函數的實現:

public void registerForCallStateChanged(Handler h, int what, Object obj) {

        Registrant r = new Registrant (h, what, obj);

        mCallStateRegistrants.add(r);

    }   

當然EVENT_CALL_STATE_CHANGE這個消息的上會有非常多原因。除了來電消息RING,還有掛斷消息NOCARRIER、電話狀態改變消息CLCC等,RIL都會作為EVENT_CALL_STATE_CHANGE報給GsmCallTracker.javaGsmCalTracker.java收到之后會。在handleMessage()相應分支中進行處理。代碼例如以下:

case EVENT_CALL_STATE_CHANGE:

pollCallsWhenSafe();

break;

進入pollCallsWhenSafe()方法中,又見消息。這回是主動查詢CLCC,查詢一下通話列表,即查詢全部的通話詳情,在這個分支 EVENT_POLL_CALLS_RESULT里獲得查詢結果:

    protected void pollCallsWhenSafe() {

        needsPoll = true;

        if (checkNoOperationsPending()) {

            lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);

            cm.getCurrentCalls(lastRelevantPoll);

        }

}

處理EVENT_POLL_CALLS_RESULT消息是在GsmCallTracker.java中:

    case EVENT_POLL_CALLS_RESULT:

        ar = (AsyncResult)msg.obj;

 

        if (msg == lastRelevantPoll) {

            if (DBG_POLL) log(

                    "handle EVENT_POLL_CALL_RESULT: set needsPoll=F");

            needsPoll = false;

            lastRelevantPoll = null;

            handlePollCalls((AsyncResult)msg.obj);

        }

break;

進入handlePollCalls()方法中。在這種方法里將揭開CLCC命令返回參數和connections集合里的元素的是什么關系?handlePollCalls()方法中會進行一個for循環操作。底層查的通話列表用DriverCall類表示。FrameWork層則抽象為GsmConnection類。在這里先看一個關於CLCC命令的樣例:

    CLCC : 1、0、2、0、0   1881234578 …..

    先是CLCC這個command。后面

    第一個參數表示 index序號,

    每二個如是0表示來電、1表示去電,

    第三個是電話狀態。

    第四個表示是數據業務還是語音業務。

    第五個表示是否是視頻會議。后面再跟着號碼。

CLCC返回的電話列表中,第一個參數就是沒路通話的編號,從1開始編號,相同能夠看到GsmCallTracker中保存的GsmConnection的集合connections集合對象是一個數組,數組編號是從0開始的,所以我們會看到會有一個dc.index == i+1;的操作。相應關系就是這里建立的。

之后會把底層查的DriverCall對象和GsmCallTracker中保存的GsmConnection對象進行比較。如DriverCall對象為空,我們本地保持的GsmConnection對象存在,非常顯然,是這路電話掛斷了。反之如過DriverCall對象有,GsmConnection對象不存在,則是一個來電:

if (conn == null && dc != null){  

if (newRinging != null) {

      phone.notifyNewRingingConnection(newRinging);

}}

在phoneBase.java里發出通知  

protected void notifyNewRingingConnectionP(Connection cn) {  

if (!mIsVoiceCapable)  

return;  

syncResult ar = new AsyncResult(null, cn, null);  

mNewRingingConnectionRegistrants.notifyRegistrants(ar);  

 }

再后面的代碼就離開Framework層了,這里把來電消息通知給上層應用:

private void registerForNotifications() {  

mCM.registerForNewRingingConnection(this,PHONE_NEW_RINGING_CONNECTION, null);  

 ….后面的代碼省略   

 }   

public void registerForNewRingingConnection(  

Handler h, int what, Object obj) {  

checkCorrectThread(h);        

mNewRingingConnectionRegistrants.addUnique(h, what, obj);  

}

PHONE_NEW_RINGING_CONNECTION這個消息發送出去之后,是在CallNotifier.java文件里處理的:

public void handleMessage(Message msg) {

        if(handleMessageMTK(msg)) {

            return;

        }

        switch (msg.what) {

            case CallStateMonitor.PHONE_NEW_RINGING_CONNECTION:

                log("RINGING... (new)");

                onNewRingingConnection((AsyncResult) msg.obj);

                mSilentRingerRequested = false;

                break;

}…省略代碼…

}

以下有對來電鈴音連接事件的處理:

/**

* Handles a "new ringing connection" event from the telephony layer.

*/

private void onNewRingingConnection(AsyncResult r) {

        Connection c = (Connection) r.result;

        log("onNewRingingConnection(): state = " + mCM.getState() + ", conn = { " + c + " }");

        Call ringing = c.getCall();

        Phone phone = ringing.getPhone(); 

if (ignoreAllIncomingCalls(phone)) {//在這里面會有去查詢黑名單或則其它操作,從而決定是否自己主動拒接來電

            

            PhoneUtils.hangupRingingCall(ringing);

            return;

        }      

…省略代碼…        

Call.State state = c.getState();//手機狀態

        // State will be either INCOMING or WAITING.

        if (VDBG) log("- connection is ringing!  state = " + state);        

        if (PhoneUtils.isRealIncomingCall(state)) {                       

PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_RINGING);           

            if (mApplication.getWiredHeadsetManager().isHeadsetPlugged() && isIncomingMuteOrVibrate()) {

                playCallWaitingTone();

            }           

            PhoneUtils.setAudioMode();

            } else {           

             mShouldSkipRing = true;

         }

        startIncomingCallQuery(c);       

        sendEmptyMessageDelayed(DELAY_AUTO_ANSWER, 3000);       

        if (VDBG) log("- onNewRingingConnection() done.");

    }

在這之后會依據獲取當前手機的狀態模式推斷是否處於摘機狀態等。

PhoneConstants.State state = mCM.getState();

推斷響鈴的模式:

public void setRingerMode(int ringerMode) {…代碼省略…}

startIncomingCallQuery(c)//取數據庫查找相應的資源,比方用什么鈴音就會去里面查找:

private void startIncomingCallQuery(Connection c) {

if (shouldStartQuery) {

setDefaultRingtoneUri(c);//設置默認的鈴聲

}

}

public void applyDeviceVolume(int device) {…代碼省略…}//設置設備音量

public Uri getDefaultRingtone(int type) {}//依據傳入的type類型設置默認的鈴音,1為TYPE_RINGTONE,2為TYPE_NOTIFICATION

public static CallerInfoToken startGetCallerInfo(Context context, Connection c,CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie,RawGatewayInfo info){}//這里面能夠看到呼叫方的號碼,和當前電話用的什么網絡。

startIncomingCallQuery中最后會運行響鈴並通知有來電了:

private void ringAndNotifyOfIncomingCall(Connection c) {

mCallModeler.onNewRingingConnection(c);

}

函數onNewRingingConnection的實現:

Call onNewRingingConnection(Connection conn) {

        Log.i(TAG, "onNewRingingConnection");

        updateDualTalkCallInfo();

        final Call call = getCallFromMap(mCallMap, conn, true);

        if (call != null) {

            updateCallFromConnection(call, conn, false);

            for (int i = 0; i < mListeners.size(); ++i) {

                mListeners.get(i).onIncoming(call);

            }

        }

        PhoneGlobals.getInstance().updateWakeState();//這里開始更新喚醒狀態

        return call;

    }

更新喚醒狀態:

void updateWakeState() {

…省略代碼…

requestWakeState(keepScreenOn ?

 WakeState.FULL : WakeState.SLEEP);

}

public void requestWakeState(WakeState ws) {

        synchronized (this) {

            if (mWakeState != ws) {

                if(is82SMBPlugged()){

                    ws = WakeState.SLEEP;

                }

                switch (ws) {

                    case PARTIAL:

                        mPartialWakeLock.acquire();

                        if (mWakeLock.isHeld()) {

                            mWakeLock.release();

                        }

                        break;

                    case FULL:

                        mWakeLock.acquire();

                        if (mPartialWakeLock.isHeld()) {

                            mPartialWakeLock.release();

                        }

                        break;

                    case SLEEP:

                    default:

                        if (mWakeLock.isHeld()) {

                            mWakeLock.release();

                        }

                        if (mPartialWakeLock.isHeld()) {

                            mPartialWakeLock.release();

                        }

                        break;

                }

                mWakeState = ws;

            }

        }

    }

以上就基本上完畢了來電流程的總結。

亮屏的流程:

點亮屏幕是從喚醒開始的:

首先依據mProximityPositive的值檢查屏幕當前是否處於遠離狀態,假設是遠離狀態的話才會去點亮,否則是不會去點亮的。

假設處於遠離狀態須要去推斷喚醒鎖是否須要更新。假設須要更新那么就會去運行更新操作。

函數wakeUpNoUpdateLocked(eventTime)的作用就是去推斷喚醒鎖是否須要更新,首先會依據mWakefulness的值去運行相應的操作,假設為WAKEFULNESS_ASLEEP,且mIPOShutdown為false時候。運行例如以下操作:

case WAKEFULNESS_ASLEEP://接收到喚醒消息

    if (!mIPOShutdown) {

        sendPendingNotificationsLocked();

        mNotifier.onWakeUpStarted();//開始喚醒

        mSendWakeUpFinishedNotificationWhenReady = true;

    }

    break;

要開始喚醒就須要捕獲亮屏堵塞個數。每捕獲一次就添加一個。

然后更新廣播鎖,即是運行函數updatePendingBroadcastLocked()。首先也是捕獲堵塞塊,也是捕獲一次就添加一個,然后發送一個MSG_BROADCAST的消息。且這個消息是異步運行的。

接收到MSG_BROADCAST這個消息后會運行sendNextBroadcast()方法。假設powerState的值等於POWER_STATE_AWAKE,那么就發送喚醒廣播。否則就發送休眠廣播。

if (powerState == POWER_STATE_AWAKE) {

sendWakeUpBroadcast();//發起喚醒廣播

} else {

sendGoToSleepBroadcast(goToSleepReason);//發送休眠廣播

}

推斷用戶界面鎖是否更新,依據mUserActivityPending的值決定是否發送異步運行的消息MSG_USER_ACTIVITY,從而運行方法sendUserActivity()。

發送的喚醒廣播最重要的操作就是運行方法:

ActivityManagerNative.getDefault().wakingUp(),這種方法不是馬上就能完畢的。可能會有一定延遲才干完畢。可是當他完畢后,且系統已經准備好就會發出一個喚醒已經結束的廣播:

if (ActivityManagerNative.isSystemReady()) {

mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,mWakeUpBroadcastDone, mHandler, 0, null, null);        

} else {

EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);

    sendNextBroadcast();

}

這個廣播的接收器例如以下:

private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver(){        

@Override

public void onReceive(Context context, Intent intent) {

     EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,

         SystemClock.uptimeMillis() - mBroadcastStartTime, 1);

            sendNextBroadcast();

        }

}

這里的廣播從發送到接收到有一定延遲。甚至可能出現有巨大延遲的狀況,由於僅僅有系統覺得亮屏結束的時候才會認定廣播接收完畢。

當確認須要更新喚醒鎖。即是wakeUpNoUpdateLocked(eventTime)的值為true時,就會去運行更新就是運行方法updatePowerStateLocked()。

updatePowerStateLocked(eventTime)這個函數非常重要,他會去更新非常多鎖的狀態代碼例如以下:

private void updatePowerStateLocked() {

if (!mSystemReady || mDirty == 0) {

     return;

    }

updateIsPoweredLocked(mDirty);

updateStayOnLocked(mDirty);

 

final long now = SystemClock.uptimeMillis();

int dirtyPhase2 = 0;

for (;;) {

    int dirtyPhase1 = mDirty;

    dirtyPhase2 |= dirtyPhase1;

    mDirty = 0;

    updateWakeLockSummaryLocked(dirtyPhase1);

updateUserActivitySummaryLocked(now, dirtyPhase1);

    if (!updateWakefulnessLocked(dirtyPhase1)) {

        break;

    }

}

 

updateDreamLocked(dirtyPhase2);

updateDisplayPowerStateLocked(dirtyPhase2);

 

if (mDisplayReady) {

     sendPendingNotificationsLocked();

}

updateSuspendBlockerLocked();

}

updateWakeLockSummaryLocked(dirtyPhase1):更新喚醒鎖主鎖,依據wakeLocked中flag值與上PowerManager.WAKE_LOCK_LEVEL_MASK進行匹配,依據各種匹配結果對mWakeLockSummary進行賦值。這里一共同擁有例如以下幾種鎖:

PARTIAL_WAKE_LOCK:保持CPU 運轉,屏幕和鍵盤燈有可能是關閉的。

SCREEN_DIM_WAKE_LOCK:保持CPU 運轉,同意保持屏幕顯示但有可能是灰的,同意關閉鍵盤燈

SCREEN_BRIGHT_WAKE_LOCK:保持CPU 運轉。同意保持屏幕高亮顯示。同意關閉鍵盤燈

FULL_WAKE_LOCK:保持CPU 運轉,保持屏幕高亮顯示,鍵盤燈也保持亮度

我們這里關注的就是FULL_WAKE_LOCK。當mWakefulness不為WAKEFULNESS_ASLEEP

mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT。假設此時mWakefulness還等於WAKEFULNESS_AWAKE那么還要或上WAKE_LOCK_STAY_AWAKE。

updateUserActivitySummaryLocked(now, dirtyPhase1):這個函數作用就依據不同的情況設置mUserActivitySummary的值,而此時就須要注意給其賦值的三個參數,各自是:按鍵亮:USER_ACTIVITY_BUTTON_BRIGHT。屏幕亮:USER_ACTIVITY_SCREEN_BRIGHT。和屏幕暗:USER_ACTIVITY_SCREEN_DIM。

updateDisplayPowerStateLocked(dirtyPhase2):這個函數的作用是更新顯示狀態鎖的。這里面最重要的newScreenState屏幕狀態值,screenBrightness屏幕亮度值。

函數中會對按鍵背光亮滅做處理:

if ( ( (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0 ) ||

       ( (mUserActivitySummary & USER_ACTIVITY_BUTTON_BRIGHT) != 0) ) {

mButtonLight.setBrightness(screenBrightness);

} else {

mButtonLight.turnOff();

}

mDisplayReady顯示是否准備好,他會通過mDisplayPowerController的requestPowerState方法推斷得出,注意這里有延時,或者是說有了反饋消息才干獲得mDisplayReady的值。requestPowerState方法返回的是mDisplayReadyLocked。而僅僅有當change的值為false,即是狀態鎖沒有更新的時候。

在有更改的時候可能會去發送更新電源狀態鎖即是運行函數sendUpdatePowerStateLocked(),而這個函數的作用就是發出一個更新電源狀態的消息:MSG_UPDATE_POWER_STATE。接收消息的地方是:

switch (msg.what) {

case MSG_UPDATE_POWER_STATE:

    updatePowerState();

    break;

}

updatePowerState():更新電源狀態,這個函數非常重要,后文重點說明。

updateSuspendBlockerLocked():這個函數主要是對mWakeLockSuspendBlocker和mDisplaySuspendBlocker的獲取和釋放進行操作。並對相應的鎖進行設值,獲取設為true。釋放設為false。

updateDreamLocked(dirtyPhase2):更新休眠鎖,這個函數是對休眠狀態下進行一些處理。當中會發出一個MSG_SANDMAN消息,處理這個消息的是handleSandman()方法。

以下重點介紹下updatePowerState()方法:

private void updatePowerState() {

…省略代碼…

…依據距離傳感器設置亮滅屏和是否激活距離傳感器…

…光感功能…

if (wantScreenOn(mPowerRequest.screenState)) {//反饋屏幕狀態亮屏 

     if (mScreenAutoBrightness >= 0 && mLightSensorEnabled && mPowerRequest.useAutoBrightness) {                

                target = mScreenAutoBrightness;

                slow = mUsingScreenAutoBrightness;

                mUsingScreenAutoBrightness = true;

            } else {           

                target = mPowerRequest.screenBrightness;

                slow = false;

                mUsingScreenAutoBrightness = false;

            }

        if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {//滅屏

                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,

                        mScreenBrightnessDimConfig);

                slow = false;               

                if (FeatureOption.MTK_AAL_SUPPORT) {

                    nativeSetScreenState(SCREEN_STATE_DIM, clampScreenBrightness(target));

                }               

            } else if (wasDim) {

                slow = false;                

                if (FeatureOption.MTK_AAL_SUPPORT) {

                    nativeSetScreenState(SCREEN_STATE_ON, clampScreenBrightness(target));

                }

            }

            animateScreenBrightness(clampScreenBrightness(target),

                    slow ?

 BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);//動態決定緩慢改變亮度還是迅速改變

        } else {            

            mUsingScreenAutoBrightness = false;

        }

  //動態運行屏幕亮或者屏幕滅

      if (!mScreenOffBecauseOfProximity || mPowerRequest.forceWakeUpEnable) {

            if (wantScreenOn(mPowerRequest.screenState)) {            

                if (!mElectronBeamOffAnimator.isStarted()) {

                    setScreenOn(true); //設置屏亮

                    mSbScreenOnIsStart = true;

                    if (mPowerRequest.blockScreenOn//亮屏處於堵塞狀態且電量等級為0,0為滅屏,1為亮屏

                            && mPowerState.getElectronBeamLevel() == 0.0f) {                    

                        blockScreenOn();//堵塞亮屏

                        mPowerState.updateElectronBeam();

                    } else {

                        unblockScreenOn();//開啟亮屏

                        if (USE_ELECTRON_BEAM_ON_ANIMATION) {

條件一直為false,里面代碼忽略

                        } else {//設置亮屏

                            mPowerState.setElectronBeamLevel(1.0f);                            

                            mPowerState.dismissElectronBeam();

                            mSbScreenOnIsStart = false;

                        }

                    }

                }

            } else {//滅屏時就會運行這里              

                if (!mElectronBeamOnAnimator.isStarted()) {

                    if (!mElectronBeamOffAnimator.isStarted()) {

                        if (mPowerState.getElectronBeamLevel() == 0.0f || mShutDownFlag_D) {

                            setScreenOn(false);//設置滅屏

                            mShutDownFlag_D = false; 

                        } else if (mPowerState.prepareElectronBeam(

                                mElectronBeamFadesConfig ?

                                        ElectronBeam.MODE_FADE :

                                                ElectronBeam.MODE_COOL_DOWN)

                                && mPowerState.isScreenOn()) {

                            mElectronBeamOffAnimator.start();

                        } else {;

                            mElectronBeamOffAnimator.end();

                        }

                    }

                }

            }

        }

        if (mustNotify

                && !mScreenOnWasBlocked

                && !mElectronBeamOnAnimator.isStarted()

                && !mElectronBeamOffAnimator.isStarted()

                && mPowerState.waitUntilClean(mCleanListener)) {

            synchronized (mLock) {//確定顯示是否准備好,亮度是否變化。異步

                if (!mPendingRequestChangedLocked) {

                    mDisplayReadyLocked = true;

                }

            }

            sendOnStateChangedWithWakelock();

        }

    }

setScreenOn(boolean on):設置亮屏的方法:

if (mPowerState.isScreenOn() != on) {//要處於亮屏狀態

     mPowerState.setScreenOn(on);

     if (on) {

          mNotifier.onScreenOn();

     } else {

         mNotifier.onScreenOff();

     }          

}

public void setScreenOn(boolean on) {// mPowerState.setScreenOn(on)

    if (mScreenOn != on) {

        mScreenOn = on;

        mScreenReady = false;

        scheduleScreenUpdate();//使屏幕更新

    }

}

public void onScreenOn() {

        try {

            mBatteryStats.noteScreenOn();

        } catch (RemoteException ex) {

        }

    }

scheduleScreenUpdate()終於會去實現接口mScreenUpdateRunnable,會依據是否亮屏mScreenOn ,電子束等級mElectronBeamLevel,屏幕亮度值mScreenBrightness這三個參數設置更新后的屏幕亮度。然后會對方法返回值進行推斷即是:

mPhotonicModulator .setState(mScreenOn, brightness)的返回值,它返回的是mChangeInProgress的值,假設為true,則覺得屏幕更新准備好,假設為false。則覺得屏幕更新沒有准備好。在這函數運行中可能去實現一個接口,而接口mTask的實現是:

   private final Runnable mTask = new Runnable() {

            public void run() {                

//申請變更知道完畢

                for (;;) {//強制反復運行,直到有條件跳出來

                    final boolean on;

                    final boolean onChanged;

                    final int backlight;

                    final boolean backlightChanged;

                    synchronized (mLock) {

                        on = mPendingOn;

                        onChanged = (on != mActualOn);

                        backlight = mPendingBacklight;

                        backlightChanged = (backlight != mActualBacklight);

                        if (!onChanged && !backlightChanged) {

                            mChangeInProgress = false;

                            break;

                        }

                        mActualOn = on;

                        mActualBacklight = backlight;

                    }

                    if (onChanged && on) {//有變化且是需點亮狀態

                        mDisplayBlanker.unblankAllDisplays();//點亮屏幕

                    }

                    if (mShutDownFlag) {

                        try {

                            Thread.sleep(mDelay);  

                        } catch (InterruptedException e) {}

                    }

                    if (backlightChanged) {//期望亮度值mPendingBacklight和真實亮度值mActualBacklight是否相等,相等時backlightChanged為false,否則為true

                        mBacklight.setBrightness(backlight);//這里會去底層設置點亮屏。非常重要。backlightChanged才會決定亮不亮屏

                        mDisplayBlanker.setBlNotify();

                        if (on) {

                            Handler monitorHandler = MessageMonitorLogger.getMsgLoggerHandler();

                            if (monitorHandler != null && monitorHandler.hasMessages(MessageMonitorLogger.START_MONITOR_EXECUTION_TIMEOUT_MSG, monitorHandler)) {                                monitorHandler.removeMessages(MessageMonitorLogger.START_MONITOR_EXECUTION_TIMEOUT_MSG, monitorHandler);

                                                           }

                        }

                    }

                    if (onChanged && !on) {//有變化且是需熄滅狀態

                        mDisplayBlanker.blankAllDisplays();//熄滅屏幕

                    }

                }

                postScreenUpdateThreadSafe();

            }

    };

   public void unblankAllDisplays() {//開啟全顯示,這里有可能會有延時

    synchronized (this) {

        nativeSetAutoSuspend(false);

        nativeSetInteractive(true);            mDisplayManagerService.unblankAllDisplaysFromPowerManager();

         mBlanked = false;

         mHDMI.hdmiPowerEnable(true); 

         mWfdShouldBypass = false;

         }

   }

unblankAllDisplaysFromPowerManager():開啟顯示,終於會依據全顯示的狀態值來確定設備開不開啟鎖,代碼例如以下:

switch (mAllDisplayBlankStateFromPowerManager) {

                case DISPLAY_BLANK_STATE_BLANKED:

                    device.blankLocked();

                    break;

                case DISPLAY_BLANK_STATE_UNBLANKED:

                    device.unblankLocked();

                    break;

            }

wakingUp()是在ActivityManagerNative.getDefault().wakingUp()調用時才運行,而要掉這里應該是監聽到了亮屏,監聽器: mPolicy.screenTurningOn(mScreenOnListener)。

private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =

            new WindowManagerPolicy.ScreenOnListener() {

        @Override

        public void onScreenOn() {

            synchronized (mLock) {

                if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {

                    mScreenOnBlockerAcquired = false;

                    mScreenOnBlocker.release();

                }

            }

        }

    }//這個非常重要

public void wakingUp() {

       if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)

                != PackageManager.PERMISSION_GRANTED) {

            throw new SecurityException("Requires permission "

                    + android.Manifest.permission.DEVICE_POWER);

        }

 

        synchronized(this) {

            mWentToSleep = false;

            updateEventDispatchingLocked();

            comeOutOfSleepIfNeededLocked();//從休眠狀態退出來

        }

    }

手機在感受到距離由近及遠的時候也會去點亮屏幕:

private final SensorEventListener mProximitySensorListener = new SensorEventListener() {//距離傳感器監聽器

        @Override

        public void onSensorChanged(SensorEvent event) {

            if (mProximitySensorEnabled) {

                final long time = SystemClock.uptimeMillis();

                final float distance = event.values[0];

                boolean positive = distance >= 0.0f && distance < mProximityThreshold;

                handleProximitySensorEvent(time, positive); // positive 的值為false,表示離開。為true,表示靠近。

 

            }

        }

    };

 

當mDisplayReady為true時會運行方法sendPendingNotificationsLocked(),這個函數的作用就是發送關於鎖結束的提示,不管是亮屏結束還是熄屏結束都會調用這里,實現的地方例如以下:

if (mSendWakeUpFinishedNotificationWhenReady) {//喚醒過程結束

    mSendWakeUpFinishedNotificationWhenReady = false;

    mNotifier.onWakeUpFinished();

}

if (mSendGoToSleepFinishedNotificationWhenReady) {//休眠過程結束

    mSendGoToSleepFinishedNotificationWhenReady = false;

    mNotifier.onGoToSleepFinished();

}

mSendWakeUpFinishedNotificationWhenReady這個值在剛進入喚醒階段就被置為了true的,所以最重要的還是什么時候mDisplayReady的值為true。

真正運行亮屏的是底層驅動去做的,而通知底層驅動的是函數:

public void setBrightness(int brightness) {// Task中的

//mBacklight.setBrightness(backlight)

setBrightness(brightness, BRIGHTNESS_MODE_USER);

}

 

public void setBrightness(int brightness, int brightnessMode) {

synchronized (this) {

     int color = brightness & 0x000000ff;

     color = 0xff000000 | (color << 16) | (color << 8) | color;

                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);

}

}

protected void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {

if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {

setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);//這個函數就會實現去通知底層驅動更新屏幕亮度

}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM