安卓手机来电亮屏流程分析
來電亮屏流程分析
本文檔是針對手機來電時候自主點亮屏幕這一流程的分析,非常自然的就將其分為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.java,GsmCalTracker.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);//這個函數就會實現去通知底層驅動更新屏幕亮度
}
}
總結
以上是生活随笔為你收集整理的安卓手机来电亮屏流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 义务兵在部队受伤面临退伍部队不给治家属不
- 下一篇: 如何选择一款合适的显示器支架显示器支架怎