android手机进入设置,在进入显示,有个休眠时间的选项。可以设置多久不操作后熄灭屏幕。android熄灭屏幕实际根据系统当前wakeLock锁的数量和类型有关,本篇文章不讨论这个问题。只是本人发现了一个奇怪的现象:
1.设置休眠时间为1分钟,在launcher界面不做任何操作,大概一分钟左右灭屏,和设置中时间相同。
2.灭屏后按电源键唤醒屏幕,在锁屏界面不做任何操作,感觉十秒左右屏幕已经熄灭,远远达不到设置中时间。
到底为什么会出现这个现象呢?我们可以猜测肯定系统有判断是否锁屏,然后对自动灭屏时间进行了不同的设置,下面验证我们的猜测。
经过一番研究代码最终发现关于是否灭屏的判断在
private boolean isBeingKeptAwakeLocked() {
return mStayOn
|| mProximityPositive
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0
|| mScreenBrightnessBoostInProgress;
}
如果该方法返回false就会灭屏,意味着其中每一项都要为false,其中和这个现象相关的为
(mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0
USER_ACTIVITY_SCREEN_BRIGHT指的是屏幕亮,指的是USER_ACTIVITY_SCREEN_DIM屏幕暗,也就意味着,mUserActivitySummary的标志位不能有亮和暗这两个属性。mUserActivitySummary主要在updateUserActivitySummaryLocked这个方法中更新。所以主要的逻辑在该方法中。
private void updateUserActivitySummaryLocked(long now, int dirty) {
// Update the status of the user activity timeout timer.
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
final int sleepTimeout = getSleepTimeoutLocked();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) {
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0) {
if (sleepTimeout >= 0) {
final long anyUserActivity = Math.max(mLastUserActivityTime,
mLastUserActivityTimeNoChangeLights);
if (anyUserActivity >= mLastWakeTime) {
nextTimeout = anyUserActivity + sleepTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
}
}
} else {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
}
if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
if ((mUserActivitySummary &
(USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
// Device is being kept awake by recent user activity
if (nextTimeout >= now && mOverriddenTimeout == -1) {
// Save when the next timeout would have occurred
mOverriddenTimeout = nextTimeout;
}
}
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
} else {
mUserActivitySummary = 0;
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
}
}
}
主要的逻辑为下面的代码
long nextTimeout = 0;//下次执行该方法的时间
final int sleepTimeout = getSleepTimeoutLocked();//未设置,一般是-1
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);//用户无操作灭屏时间,和设置中的休眠时间有关系。
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);//暗屏持续时间
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
我们可以看出其中的核心就是screenOffTimeout,这个时间的多少和当前系统时间的比较影响mUserActivitySummary的值,从而影响是否灭屏。
所以核心为getScreenOffTimeoutLocked()
private int getScreenOffTimeoutLocked(int sleepTimeout) {
int timeout = mScreenOffTimeoutSetting;
if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
}
if (mUserActivityTimeoutOverrideFromWindowManager >= 0) {
timeout = (int)Math.min(timeout, mUserActivityTimeoutOverrideFromWindowManager);
}
if (sleepTimeout >= 0) {
timeout = Math.min(timeout, sleepTimeout);
}
return Math.max(timeout, mMinimumScreenOffTimeoutConfig);
}
经过我们打log发现在锁屏界面出现时mUserActivityTimeoutOverrideFromWindowManager值为10000,也就是10s,符合我们的观察。再搜索代码发现
在frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
private void applyUserActivityTimeout(State state) {
if (state.isKeyguardShowingAndNotOccluded()
&& state.statusBarState == StatusBarState.KEYGUARD
&& !state.qsExpanded) {
mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
} else {
mLpChanged.userActivityTimeout = -1;
}
}
可以看出判断如果有锁屏的话设置userActivityTimeout为KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
public static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;