【Android】屏幕超时休眠
前言
屏幕超时休眠指的是在设备一段时间没有操作后,自动关闭屏幕显示以节省电量并防止误触。当屏幕进入休眠状态时,通常会关闭屏幕背光,但设备可能仍在运行后台进程。
正文
Settings应用相关
Settings应用的屏幕超时休眠界面相关代码定位到:
packages/apps/Settings/res/xml/display_settings.xml
屏幕超时休眠的控件的key值为screen_timeout。屏幕超时休眠列表选项信息,根据key值找到控件,随后根据android:entries和android:entryValues相关代码定位到:
packages/apps/Settings/res/values/arrays.xml
相关Controller代码定位到:
packages/apps/Settings/src/com/android/settings/display/TimeoutPreferenceController.java
@Override
public void updateState(Preference preference) {
final TimeoutListPreference timeoutListPreference = (TimeoutListPreference) preference;
final long currentTimeout = Settings.System.getLong(mContext.getContentResolver(),
SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE);//获取到设置的屏幕超时休眠时间
timeoutListPreference.setValue(String.valueOf(currentTimeout));
final DevicePolicyManager dpm =
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
if (dpm != null) {
final RestrictedLockUtils.EnforcedAdmin admin =
RestrictedLockUtils.checkIfMaximumTimeToLockIsSet(mContext);
final long maxTimeout =
dpm.getMaximumTimeToLock(null /* admin */, UserHandle.myUserId());
timeoutListPreference.removeUnusableTimeouts(maxTimeout, admin);
}
updateTimeoutPreferenceDescription(timeoutListPreference, currentTimeout);//更新屏幕超时休眠时间描述
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT,
UserHandle.myUserId());
if(admin != null) {
timeoutListPreference.removeUnusableTimeouts(0/* disable all*/, admin);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
try {
int value = Integer.parseInt((String) newValue);//获取到设置的新的屏幕超时休眠时间
Settings.System.putInt(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, value);//设置新的屏幕超时休眠时间
updateTimeoutPreferenceDescription((TimeoutListPreference) preference, value);//更新屏幕超时休眠时间描述
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist screen timeout setting", e);
}
return true;
}
//更新屏幕超时休眠时间描述
private void updateTimeoutPreferenceDescription(TimeoutListPreference preference,
long currentTimeout) {
final String summary;
// 省略部分源代码
preference.setSummary(summary);//设置描述信息
}
属性值相关
屏幕超时休眠默认时间,定位到:
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
<integer name="def_screen_off_timeout">15000</integer>
默认时间属性值是写在SQLite中,具体详情见:
packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
屏幕超时休眠默认最低时间,定位到:
frameworks/base/core/res/res/values/config.xml
<!-- User activity timeout: Minimum screen off timeout in milliseconds.
Sets a lower bound for the {@link Settings.System#SCREEN_OFF_TIMEOUT} setting
which determines how soon the device will go to sleep when there is no
user activity.
This value must be greater than zero, otherwise the device will immediately
fall asleep again as soon as it is awoken.
-->
<integer name="config_minimumScreenOffTimeout">10000</integer>
由上述注释信息,可知屏幕超时休眠默认最低时间需要设置在 \(0\) 以上。既然如此,我们如果设置的值是一个小于最低默认值的数值,甚至是一个小于等于 \(0\) 的数值又会发生什么事情呢?
在framework/base目录下搜 \(screen_off_timeout\) 可以定位到:
core/java/android/provider/Settings.java
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR;//屏幕超时休眠时间校验器
//省略部分源代码
static {
//省略部分源代码
VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);//添加校验器
//省略部分源代码
}
于是查看校验器NON_NEGATIVE_INTEGER_VALIDATOR相关代码,定位到:
framework/base/core/java/android/provider/SettingsValidators.java
public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
@Override
public boolean validate(@Nullable String value) {
try {
return Integer.parseInt(value) >= 0;
} catch (NumberFormatException e) {
return false;
}
}
};
由上述校验器代码可知,若传入的值是个负数,校验器会对传入的值进行异常抛出,保证代码不崩溃。
项目实战
修改休眠时间列表
根据Settings应用的xml界面的android:entries和android:entryValues相关代码定位到:
packages/apps/Settings/res/values/arrays.xml
直接添加item即可。
若新增的item的value低于屏幕超时休眠默认最低时间,需要修改系统默认最低值
frameworks/base/core/res/res/values/config.xml
<integer name="config_minimumScreenOffTimeout">10000</integer>
修改系统默认屏幕超时休眠时间
修改defaults.xml下的def_screen_off_timeout属性值即可。
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
<integer name="def_screen_off_timeout">15000</integer>
三方app自定义屏幕超时休眠时间
首先,在Settings应用中添加一个广播,在源代码中添加一个action来接收即可,定位到路径:
packages/apps/Settings/AndroidManifest.xml
<!-- 找到一个已有的receiver,或者新增一个receiver都是可行的,随后声明一个自定义ACTION -->
<receiver android:name=".SettingsInitialize">
<intent-filter>
<action android:name="自定义ACTION"/>
<action android:name="android.intent.action.USER_INITIALIZE"/>
<action android:name="android.intent.action.PRE_BOOT_COMPLETED"/>
</intent-filter>
</receiver>
在广播接收器的类中实现接收的逻辑
packages/apps/Settings/src/com/android/settings/SettingsInitialize.java
@Override
public void onReceive(Context context, Intent broadcast) {
//begin:新增的代码
String action = broadcast.getAction();
if (context.getString(自定义ACTION的字符串资源路径).equals(action)) {
final long currentTimeout = Settings.System.getLong(context.getContentResolver(),
SCREEN_OFF_TIMEOUT, TimeoutPreferenceController.FALLBACK_SCREEN_TIMEOUT_VALUE);
int value = broadcast.getIntExtra("screen_off_timeout", (int)currentTimeout);
Settings.System.putInt(context.getContentResolver(), SCREEN_OFF_TIMEOUT, value);
return ;
}
//end:新增的代码
final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
UserInfo userInfo = um.getUserInfo(UserHandle.myUserId());
final PackageManager pm = context.getPackageManager();
managedProfileSetup(context, pm, broadcast, userInfo);
webviewSettingSetup(context, pm, userInfo);
refreshExistingShortcuts(context);
}
在自己的三方应用中添加如下核心代码
Intent screenTimeoutIntent = new Intent("自定义ACTION");
int value = 20000;//新定义的屏幕超时休眠时间
screenTimeoutIntent.putExtra("screen_off_timeout", value);
//若Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND找不到,就用0x01000000硬编码替换
screenTimeoutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
sendBroadcast(screenTimeoutIntent);//发出广播,通知更新屏幕超时休眠时间
若是希望可以自定义的屏幕超时休眠时间可以低于系统默认最低超时休眠时间,则需要连同系统默认休眠时间一起修改。