Android5.1 手机Settings加入从不休眠

时间:2022-05-30 20:35:17

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);
    }