安卓手机来电亮屏流程分析

来电亮屏流程分析

本文档是针对手机来电时候自主点亮屏幕这一流程的分析,很自然的就将其分为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);//这个函数就会实现去通知底层驱动更新屏幕亮度

}

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 15:06:53

安卓手机来电亮屏流程分析的相关文章

安卓手机无线投屏电脑 三种方法轻松搞

在手机上看视频,已经是我们现在最主流的娱乐方式.不过,长时间看小屏幕对眼睛可受不了,而且一些4K.1080P的大片还是在大屏幕上更有视觉效果.这时该怎么办呢,有没有什么办法可以将手机屏幕投射到电脑屏幕上,下面简单几步教你安卓手机无线投屏电脑.手机投屏到电脑其实主要使用的是WiFi传输,这种技术名为"Miracast".简单来说,"Miracast"就是通过"WiFi Display"认证的设备.有了这一功能后,移动端的音视频文件就可以分享到电脑上

python3:判断手机的亮屏状态

在用python对手机做一些自动化操作时,常常会判断手机的亮屏状态,知晓手机的亮屏状态后才好做进一步的动作,如给屏幕解锁等.  用于了解手机的亮屏情况,有一个adb命令可用: adb shell dumpsys window polic 分别在灭屏和亮屏的情况下run这个adb command,看打印出的info有何不同? 从图中可看出, 亮屏和灭屏的状态,有几行是有明显不一样的.任挑一行用来作为check数据都是可以的,为了简便,我们挑最明显最短的: mAwake=false为详细明了解che

Android让手机主动亮屏的代码

我们在做电子阅读器的时候可能会要求屏幕保持常亮,不希望它熄灭.它的原理也是利用系统服务,来操纵底层设备. 一.系统服务——PowerManager PowerManager.java就是管理我们电源方面的功能的,当然也包括我们屏幕的亮和熄灭. PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager)getSystemService(POWER

哪种安卓手机游戏录屏更好?

安卓手机录屏软件大家都知道很多,关于安卓录屏软件很多人都找不到可以录制游戏的软件.有的手机自带录屏软件,而有些手机不带录屏软件,想用手机录制游戏全过程,却不知所措,针对大家的烦恼,小编也是精挑细选的找出了这样一款神奇的软件,想知道是什么软件吗?来一起接着看下去. 录屏大师http://www.xunjieshipin.com/download-airscreen 安卓录屏软件http://www.pc6.com/softview/SoftView_600540.html 软件介绍: 迅捷录屏大师

安卓手机无线投屏软件哪个好?

手机投屏已经不是新鲜的事情了,有些电脑时有自带录屏功能的,但是并不是所有的电脑都具备这项功能,有时候甚至会觉得特别的麻烦,还要找很多投屏软件来进行操作,那么到底有没有一款软件可以让宝宝们操作起来更加方便快捷呢?所有小编找到了今天要介绍的这款软件,个人觉得还是蛮不错的,你们喜欢的话不妨去试试. 录屏大师http://dl.pconline.com.cn/download/1760585.html安卓投屏软件http://dl.pconline.com.cn/download/1760585.htm

【Rayeager PX2分享】修改安卓开机后进入主屏幕流程分析

在之前楼主在学习了Android的启动流程后,继续学了下去,然后看了上面这位博主的分享,便对修改主屏有明确思路了 开始尝试修改开机后首次进入的界面,首先楼主先写了一个简单的apk,主要最初默认的程序中在AndroidMain里fiter里加了句 <category android:name="android.intent.category.HOME" />主要在android启动后选择主屏幕可以找到这个apk. 显示hello PX2样子如下 生成apk,然后在linux环

js控制手机保持亮屏的库,解决h5移动端,自动息屏问题

一些说明:我用Laya(ts)开发小游戏,有需要保持手机屏幕常亮的需求(非必须的),然后作为小白的我就在网上找到了这个库,大概了解下,应该是通过播放空视频的原理来保持手机屏幕常亮,然后就放到项目中试了下,确实是有用的,能达到屏幕常亮的效果,可惜就是fps从稳定的60帧变为40(或者更低)-60之间摇摆不定,画面很卡,看来我这个游戏是用不了,要找下别的方法,也或者是我使用不当,不过感觉这个库还是很厉害,故记录分享下,转载地址:https://github.com/richtr/NoSleep.js

指纹解锁亮屏时间 Log 分析

极力推荐Android 开发大总结文章:欢迎收藏 Android 开发技术文章大总结 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 1.解锁指纹,发送指纹中断Log 2.认证指纹,计算指纹耗时 3.指纹认证成功,keyguard 响应解锁屏流程 4.keyguard 解锁结束,开启动Launcher至绘制工作 5.Launcher 绘制完成,隐藏Keyguard 6.点亮屏幕结束,统计亮屏时间 1. 解锁指纹,发送指纹中断Log 从kernel lo

检测手机屏幕是否亮屏解锁

通过adb命令获取手机是否锁屏状态,可以通过下面指令:1.adb shell dumpsys window policy^|grep isStatusBarKeyguard2.adb shell dumpsys window policy^|grep mShowingLockscreen 运行第1条命令,获取到结果,如下: isStatusBarKeyguard=false mFocusedWindow=Window{3c2b801 u0 com.tencent.mm/com.tencent.m