Settings的apk的目录是在packages\apps\Settings下,由于我们添加的从不休眠是在显示项里面,所以我们就直接看DisplaySettings.java的代码了。
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Activity activity = getActivity(); final ContentResolver resolver = activity.getContentResolver(); //加入display_settings的Preferences addPreferencesFromResource(R.xml.display_settings); mScreenSaverPreference = findPreference(KEY_SCREEN_SAVER); if (mScreenSaverPreference != null && getResources().getBoolean( com.android.internal.R.bool.config_dreamsSupported) == false) { getPreferenceScreen().removePreference(mScreenSaverPreference); } //找到屏幕休眠时间的ListPreference mScreenTimeoutPreference = (ListPreference) findPreference(KEY_SCREEN_TIMEOUT); final long currentTimeout = Settings.System.getLong(resolver, SCREEN_OFF_TIMEOUT,//从settings数据库中获取屏幕休眠时间 FALLBACK_SCREEN_TIMEOUT_VALUE); //mScreenTimeoutPreference.setValue(String.valueOf(currentTimeout)); // long timeoutValue = (currentTimeout == Integer.MAX_VALUE) ? -1 : currentTimeout;//如果从数据库得到最大值,改成-1 mScreenTimeoutPreference.setValue(String.valueOf(timeoutValue)); // mScreenTimeoutPreference.setOnPreferenceChangeListener(this);//监听变化 disableUnusableTimeouts(mScreenTimeoutPreference); //updateTimeoutPreferenceDescription(currentTimeout); updateTimeoutPreferenceDescription(timeoutValue);//更新屏幕上的信息
我们先看下display_settings.xml文件中screen_timeout这个ListPreference;
<ListPreference android:key="screen_timeout" android:title="@string/screen_timeout" android:summary="@string/screen_timeout_summary" android:persistent="false" android:entries="@array/screen_timeout_entries" android:entryValues="@array/screen_timeout_values" />
接下来我们看下updateTimeoutPreferenceDescription这个函数,这个函数最后调用preference.setSummary主要更新屏幕上的信息
private void updateTimeoutPreferenceDescription(long currentTimeout) { ListPreference preference = mScreenTimeoutPreference; String summary; if (currentTimeout == -1) {//如果为-1,string为永不 // Unsupported value summary = preference.getContext().getString(R.string.screen_never_timeout_summary); } else if (currentTimeout < -1) { // Unsupported value summary = ""; } else { final CharSequence[] entries = preference.getEntries(); final CharSequence[] values = preference.getEntryValues(); if (entries == null || entries.length == 0) { summary = ""; } else { int best = 0; for (int i = 0; i < values.length; i++) { long timeout = Long.parseLong(values[i].toString()); /*if (currentTimeout >= timeout) { best = i; }*/ if (currentTimeout >= timeout && timeout > 0) {//timeout为了过滤-1 best = i; } } summary = preference.getContext().getString(R.string.screen_timeout_summary, entries[best]); } } preference.setSummary(summary); }
先看下R.string.screen_timeout_summary这个string
<string name="screen_timeout_summary" msgid="327761329263064327">"无操作<xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g>后"</string>
可以看下dream_timeout_entries的xml文件
<string-array name="dream_timeout_entries"> <item msgid="3149294732238283185">"永不"</item> <item msgid="2194151041885903260">"15 秒"</item> <item msgid="5892295237131074341">"30 秒"</item> <item msgid="3538441365970038213">"1 分钟"</item> <item msgid="412343871668955639">"2 分钟"</item> <item msgid="5076853889688991690">"5 分钟"</item> <item msgid="1903860996174927898">"10 分钟"</item> <item msgid="6415509612413178727">"30 分钟"</item> </string-array>
因此两者组合起来会有"无操作5分钟后",这样的效果。
另外onPreferenceChange这个函数,是当你选择选项变化时调用。
public boolean onPreferenceChange(Preference preference, Object objValue) { final String key = preference.getKey(); if (KEY_SCREEN_TIMEOUT.equals(key)) {//当时屏幕休眠时间那一项改变 /*try { int value = Integer.parseInt((String) objValue); Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, value); Log.e(TAG, "DisplaySettings:currentTimeout:" + value); updateTimeoutPreferenceDescription(value); } catch (NumberFormatException e) { Log.e(TAG, "could not persist screen timeout setting", e); }*/ int value = Integer.parseInt((String) objValue);// 先获取值 int oldvalue = Integer.parseInt(((ListPreference)preference).getValue()); if (value != oldvalue) { int timeoutValue = ( -1 == value) ? Integer.MAX_VALUE : value;//如果值为-1,变为最大值 try { Log.e(TAG, "timeoutValue is: " + timeoutValue); Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, timeoutValue);//保存到settings这个数据库中 updateTimeoutPreferenceDescription(value);//更新显示部分 } catch (NumberFormatException e) { Log.e(TAG, "could not persist screen timeout setting", e); } } } if (KEY_FONT_SIZE.equals(key)) { writeFontSizePreference(objValue); } if (preference == mAutoBrightnessPreference) { boolean auto = (Boolean) objValue; Settings.System.putInt(getContentResolver(), SCREEN_BRIGHTNESS_MODE, auto ? SCREEN_BRIGHTNESS_MODE_AUTOMATIC : SCREEN_BRIGHTNESS_MODE_MANUAL); } if (preference == mLiftToWakePreference) { boolean value = (Boolean) objValue; Settings.Secure.putInt(getContentResolver(), WAKE_GESTURE_ENABLED, value ? 1 : 0); } if (preference == mDozePreference) { boolean value = (Boolean) objValue; Settings.Secure.putInt(getContentResolver(), DOZE_ENABLED, value ? 1 : 0); } return true; }
我们可以看下screen_timeout_values的xml文件,在最后面添加了一个-1,也就是当选择"永不“的时候会传入一个-1,这时候会变成一个Integer.MAX_VALUE 存数据库。
<string-array name="screen_timeout_values" translatable="false"> <!-- Do not translate. --> <item>15000</item> <!-- Do not translate. --> <item>30000</item> <!-- Do not translate. --> <item>60000</item> <!-- Do not translate. --> <item>120000</item> <!-- Do not translate. --> <item>300000</item> <!-- Do not translate. --> <item>600000</item> <!-- Do not translate. --> <item>1800000</item> <item>-1</item> </string-array>
这样就完成了在settings中添加永不休眠这个功能。
下面我们再来看下PowerManagerService中如何将settings添加的这个功能生效。
在PowerManagerService中的systemReady函数中注册了对settings数据库SCREEN_OFF_TIMEOUT的监听
resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver, UserHandle.USER_ALL);而mSettingsObserver的类如下:
private final class SettingsObserver extends ContentObserver { public SettingsObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange, Uri uri) { synchronized (mLock) { handleSettingsChangedLocked(); } } }
再看handleSettingsChangedLocked函数:
private void handleSettingsChangedLocked() { updateSettingsLocked(); updatePowerStateLocked(); }
private void updateSettingsLocked() { final ContentResolver resolver = mContext.getContentResolver(); mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver, Settings.Secure.SCREENSAVER_ENABLED, mDreamsEnabledByDefaultConfig ? 1 : 0, UserHandle.USER_CURRENT) != 0); mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0, UserHandle.USER_CURRENT) != 0); mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, mDreamsActivatedOnDockByDefaultConfig ? 1 : 0, UserHandle.USER_CURRENT) != 0); mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver, Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT, UserHandle.USER_CURRENT);//获取settings数据库中SCREEN_OFF_TIMEOUT的值
更新了mScreenOffTimeoutSetting之后,会去调用updatePowerStateLocked函数,更新整个PowerManagerService的状态:
通过在updateUserActivitySummaryLocked函数中调用getScreenOffTimeoutLocked函数:
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);//调用getScreenOffTimeoutLocked函数 final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
在getScreenOffTimeoutLocked函数中用mScreenOffTimeoutSetting这个成员变量:
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); }