ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
前面曾经提到过userActivity的作用,此处举一个例子加深读者对它的印象: 打开手机,并解锁进入桌面。如果在规定时间内不操作手机,那么屏幕将变暗,最后关闭。在此过程中,如果触动屏幕,屏幕又会重新变亮。这个触动屏幕的操作将导致userActivity函数被调用。 在上述例子中实际上包含了两方面的内容: - 不操作手机,屏幕将变暗,最后关闭。在PMS中,这是一个状态切换的过程。 - 操作手机,将触发userActivity,此后屏幕的状态将重置。 来看以下代码: **PowerManagerService.java::userActivity** ~~~ public voiduserActivity(long time, boolean noChangeLights) { ......//检查调用进程是否有DEVICE_POWER的权限 userActivity(time, -1, noChangeLights, OTHER_EVENT, false); } ~~~ 此处将调用另外一个同名函数。注意第三个参数的值OTHER_EVENT。系统一共定义了三种事件,分别是OTHER_EVENT(除按键、触摸屏外的事件)、BUTTON_EVENT(按键事件)和TOUCH_EVENT(触摸屏事件)。它们主要为BatteryStatsService进行电量统计时使用,例如触摸屏事件的耗电量和按键事件的耗电量等。 **PowerManagerService.java::userActivity** ~~~ private void userActivity(long time, long timeoutOverride, boolean noChangeLights,inteventType, boolean force) { if(((mPokey & POKE_LOCK_IGNORE_TOUCH_EVENTS) != 0) && (eventType == TOUCH_EVENT)) { //mPokey和输入事件的处理策略有关。如果此处的if判断得到满足,表示忽略TOUCH_EVENT return; } synchronized (mLocks) { if(isScreenTurningOffLocked()) { return; } if(mProximitySensorActive && mProximityWakeLockCount == 0) mProximitySensorActive = false;//控制接近传感器 if(mLastEventTime <= time || force) { mLastEventTime = time; if((mUserActivityAllowed && !mProximitySensorActive) || force) { if (eventType == BUTTON_EVENT && !mUseSoftwareAutoBrightness) { mUserState =(mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT); } else { mUserState |=SCREEN_BRIGHT;//设置用户事件导致的mUserState } ......//通知BatteryStatsService进行电量统计 mBatteryStats.noteUserActivity(uid,eventType); //重新计算WakeLock状态 mWakeLockState = mLocks.reactivateScreenLocksLocked(); setPowerState(mUserState | mWakeLockState, noChangeLights, WindowManagerPolicy.OFF_BECAUSE_OF_USER); //重新开始屏幕计时 setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT); } } } //mPolicy指向PhoneWindowManager,用于和WindowManagerService交互 if(mPolicy != null) { mPolicy.userActivity(); } } ~~~ 有了前面分析的基础,相信很多读者都会觉得userActivity函数很简单。在前面的代码中,通过setPowerState点亮了屏幕,那么经过一段时间后发生的屏幕状态切换在哪儿进行呢?来看setTimeoutLocked函数的代码: **PowerManagerService.java::setTimeoutLocked** ~~~ private void setTimeoutLocked(long now, final longoriginalTimeoutOverride, intnextState) { //在本例中,nextState为SCREEN_BRIGHT,originalTimeoutOverride为-1 longtimeoutOverride = originalTimeoutOverride; if(mBootCompleted) { synchronized (mLocks) { long when = 0; if(timeoutOverride <= 0) { switch (nextState) { case SCREEN_BRIGHT: when = now + mKeylightDelay;//得到一个超时时间 break; case SCREEN_DIM: if (mDimDelay >= 0) { when = now + mDimDelay; break; } ...... case SCREEN_OFF: synchronized (mLocks) { when = now +mScreenOffDelay; } break; default: when = now; break; } }......//处理timeoutOverride大于零的情况,无非就是设置状态和超时时间 mHandler.removeCallbacks(mTimeoutTask); mTimeoutTask.nextState = nextState; mTimeoutTask.remainingTimeoutOverride = timeoutOverride > 0 ? (originalTimeoutOverride- timeoutOverride) : -1; //抛送一个mTimeoutTask交给mHandler执行,执行时间为when秒后 mHandler.postAtTime(mTimeoutTask, when); mNextTimeout = when; //调试用 } } } ~~~ 接下来看mTimeOutTask的代码: ~~~ private class TimeoutTask implements Runnable { intnextState; longremainingTimeoutOverride; publicvoid run() { synchronized (mLocks) { if(nextState == -1)return; mUserState = this.nextState; //调用setPowerState去真正改变屏幕状态 setPowerState(this.nextState| mWakeLockState); long now = SystemClock.uptimeMillis(); switch (this.nextState) { case SCREEN_BRIGHT: if (mDimDelay >= 0) {//设置下一个状态为SCREEN_DIM setTimeoutLocked(now,remainingTimeoutOverride, SCREEN_DIM); break; } case SCREEN_DIM://设置下一个状态为SCREEN_OFF setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_OFF); break; }......//省略花括号 } ~~~ TimeoutTask就是用来切换屏幕状态的,相信不少读者已经在网络上见过一个和PMS屏幕状态切换相关的图(其实就是TimeoutTask的工作流程解释),对此,本章就不再介绍了,希望读者能通过直接阅读源码加深理解。