來電亮屏流程分析
本文檔是針對手機來電時候自主點亮屏幕這一流程的分析,非常自然的就將其分為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);//這個函數就會實現去通知底層驅動更新屏幕亮度
}
}