Loading res/values/attrs.xml +8 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,14 @@ <attr name="allowDynamicSummaryInSlice" format="boolean" /> </declare-styleable> <declare-styleable name="PreferenceScreen"> <!-- Determines if static preferences defined in addStaticPreferences are added before or after the radio buttons --> <attr name="staticPreferenceLocation"> <enum name="prepend" value="0" /> <enum name="append" value="1" /> </attr> </declare-styleable> <!-- For DotsPageIndicator --> <declare-styleable name="DotsPageIndicator"> <attr name="dotDiameter" format="dimension" /> Loading res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -5406,6 +5406,12 @@ <!-- Battery saver: Label for preference to turn on battery saver automatically when battery is low [CHAR_LIMIT=40] --> <string name="battery_saver_auto_title">Turn on automatically</string> <!-- Battery saver: Label for preference to indicate there is no battery saver schedule [CHAR_LIMIT=40] --> <string name="battery_saver_auto_no_schedule">No schedule</string> <!-- Battery saver: Title for battery saver schedule screen [CHAR_LIMIT=40] --> <string name="battery_saver_schedule_settings_title">Set a schedule</string> <!-- Battery saver: Label for seekbar to change battery saver threshold [CHAR_LIMIT=40] --> <string name="battery_saver_seekbar_title">At <xliff:g id="percent">%1$s</xliff:g></string> Loading res/xml/battery_saver_schedule_settings.xml 0 → 100644 +23 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2018 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/battery_saver_schedule_settings_title" settings:staticPreferenceLocation="append"> </PreferenceScreen > src/com/android/settings/core/PreferenceXmlParserUtils.java +23 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class PreferenceXmlParserUtils { private static final List<String> SUPPORTED_PREF_TYPES = Arrays.asList( "Preference", "PreferenceCategory", "PreferenceScreen", "com.android.settings.widget.WorkOnlyCategory"); public static final int PREPEND_VALUE = 0; public static final int APPEND_VALUE = 1; /** * Flag definition to indicate which metadata should be extracted when Loading Loading @@ -84,6 +86,7 @@ public class PreferenceXmlParserUtils { int FLAG_NEED_KEYWORDS = 1 << 8; int FLAG_NEED_SEARCHABLE = 1 << 9; int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10; int FLAG_NEED_PREF_APPEND = 1 << 11; } public static final String METADATA_PREF_TYPE = "type"; Loading @@ -97,6 +100,7 @@ public class PreferenceXmlParserUtils { public static final String METADATA_SEARCHABLE = "searchable"; public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = "allow_dynamic_summary_in_slice"; public static final String METADATA_APPEND = "staticPreferenceLocation"; private static final String ENTRIES_SEPARATOR = "|"; Loading Loading @@ -184,14 +188,13 @@ public class PreferenceXmlParserUtils { // Parse next until start tag is found } final int outerDepth = parser.getDepth(); final boolean hasPrefScreenFlag = hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN); do { if (type != XmlPullParser.START_TAG) { continue; } final String nodeName = parser.getName(); if (!hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN) && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) { if (!hasPrefScreenFlag && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) { continue; } if (!SUPPORTED_PREF_TYPES.contains(nodeName) && !nodeName.endsWith("Preference")) { Loading @@ -199,8 +202,14 @@ public class PreferenceXmlParserUtils { } final Bundle preferenceMetadata = new Bundle(); final AttributeSet attrs = Xml.asAttributeSet(parser); final TypedArray preferenceAttributes = context.obtainStyledAttributes(attrs, R.styleable.Preference); TypedArray preferenceScreenAttributes = null; if (hasPrefScreenFlag) { preferenceScreenAttributes = context.obtainStyledAttributes( attrs, R.styleable.PreferenceScreen); } if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_TYPE)) { preferenceMetadata.putString(METADATA_PREF_TYPE, nodeName); Loading Loading @@ -236,6 +245,10 @@ public class PreferenceXmlParserUtils { preferenceMetadata.putBoolean(METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE, isDynamicSummaryAllowed(preferenceAttributes)); } if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_APPEND) && hasPrefScreenFlag) { preferenceMetadata.putBoolean(METADATA_APPEND, isAppended(preferenceScreenAttributes)); } metadata.add(preferenceMetadata); preferenceAttributes.recycle(); Loading Loading @@ -325,7 +338,12 @@ public class PreferenceXmlParserUtils { false /* default */); } private static String getKeywords(TypedArray styleAttributes) { return styleAttributes.getString(R.styleable.Preference_keywords); private static String getKeywords(TypedArray styledAttributes) { return styledAttributes.getString(R.styleable.Preference_keywords); } private static boolean isAppended(TypedArray styledAttributes) { return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation, PREPEND_VALUE) == APPEND_VALUE; } } src/com/android/settings/widget/RadioButtonPickerFragment.java +29 −2 Original line number Diff line number Diff line Loading @@ -22,10 +22,12 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import androidx.annotation.LayoutRes; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; Loading @@ -34,16 +36,23 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.PreferenceXmlParserUtils; import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag; import com.android.settingslib.widget.CandidateInfo; import java.io.IOException; import java.util.List; import java.util.Map; import org.xmlpull.v1.XmlPullParserException; public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements RadioButtonPreference.OnClickListener { @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting static final String EXTRA_FOR_WORK = "for_work"; private static final String TAG = "RadioButtonPckrFrgmt"; @VisibleForTesting boolean mAppendStaticPreferences = false; private final Map<String, CandidateInfo> mCandidates = new ArrayMap<>(); Loading @@ -69,6 +78,19 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { super.onCreatePreferences(savedInstanceState, rootKey); try { // Check if the xml specifies if static preferences should go on the top or bottom final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(getContext(), getPreferenceScreenResId(), MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND); mAppendStaticPreferences = metadata.get(0) .getBoolean(PreferenceXmlParserUtils.METADATA_APPEND); } catch (IOException e) { Log.e(TAG, "Error trying to open xml file", e); } catch (XmlPullParserException e) { Log.e(TAG, "Error parsing xml", e); } updateCandidates(); } Loading Loading @@ -142,7 +164,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr final String systemDefaultKey = getSystemDefaultKey(); final PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); if (!mAppendStaticPreferences) { addStaticPreferences(screen); } final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId(); if (shouldShowItemNone()) { Loading @@ -168,6 +192,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr } } mayCheckOnlyRadioButton(); if (mAppendStaticPreferences) { addStaticPreferences(screen); } } @VisibleForTesting Loading Loading
res/values/attrs.xml +8 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,14 @@ <attr name="allowDynamicSummaryInSlice" format="boolean" /> </declare-styleable> <declare-styleable name="PreferenceScreen"> <!-- Determines if static preferences defined in addStaticPreferences are added before or after the radio buttons --> <attr name="staticPreferenceLocation"> <enum name="prepend" value="0" /> <enum name="append" value="1" /> </attr> </declare-styleable> <!-- For DotsPageIndicator --> <declare-styleable name="DotsPageIndicator"> <attr name="dotDiameter" format="dimension" /> Loading
res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -5406,6 +5406,12 @@ <!-- Battery saver: Label for preference to turn on battery saver automatically when battery is low [CHAR_LIMIT=40] --> <string name="battery_saver_auto_title">Turn on automatically</string> <!-- Battery saver: Label for preference to indicate there is no battery saver schedule [CHAR_LIMIT=40] --> <string name="battery_saver_auto_no_schedule">No schedule</string> <!-- Battery saver: Title for battery saver schedule screen [CHAR_LIMIT=40] --> <string name="battery_saver_schedule_settings_title">Set a schedule</string> <!-- Battery saver: Label for seekbar to change battery saver threshold [CHAR_LIMIT=40] --> <string name="battery_saver_seekbar_title">At <xliff:g id="percent">%1$s</xliff:g></string> Loading
res/xml/battery_saver_schedule_settings.xml 0 → 100644 +23 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2018 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/battery_saver_schedule_settings_title" settings:staticPreferenceLocation="append"> </PreferenceScreen >
src/com/android/settings/core/PreferenceXmlParserUtils.java +23 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class PreferenceXmlParserUtils { private static final List<String> SUPPORTED_PREF_TYPES = Arrays.asList( "Preference", "PreferenceCategory", "PreferenceScreen", "com.android.settings.widget.WorkOnlyCategory"); public static final int PREPEND_VALUE = 0; public static final int APPEND_VALUE = 1; /** * Flag definition to indicate which metadata should be extracted when Loading Loading @@ -84,6 +86,7 @@ public class PreferenceXmlParserUtils { int FLAG_NEED_KEYWORDS = 1 << 8; int FLAG_NEED_SEARCHABLE = 1 << 9; int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10; int FLAG_NEED_PREF_APPEND = 1 << 11; } public static final String METADATA_PREF_TYPE = "type"; Loading @@ -97,6 +100,7 @@ public class PreferenceXmlParserUtils { public static final String METADATA_SEARCHABLE = "searchable"; public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = "allow_dynamic_summary_in_slice"; public static final String METADATA_APPEND = "staticPreferenceLocation"; private static final String ENTRIES_SEPARATOR = "|"; Loading Loading @@ -184,14 +188,13 @@ public class PreferenceXmlParserUtils { // Parse next until start tag is found } final int outerDepth = parser.getDepth(); final boolean hasPrefScreenFlag = hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN); do { if (type != XmlPullParser.START_TAG) { continue; } final String nodeName = parser.getName(); if (!hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN) && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) { if (!hasPrefScreenFlag && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) { continue; } if (!SUPPORTED_PREF_TYPES.contains(nodeName) && !nodeName.endsWith("Preference")) { Loading @@ -199,8 +202,14 @@ public class PreferenceXmlParserUtils { } final Bundle preferenceMetadata = new Bundle(); final AttributeSet attrs = Xml.asAttributeSet(parser); final TypedArray preferenceAttributes = context.obtainStyledAttributes(attrs, R.styleable.Preference); TypedArray preferenceScreenAttributes = null; if (hasPrefScreenFlag) { preferenceScreenAttributes = context.obtainStyledAttributes( attrs, R.styleable.PreferenceScreen); } if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_TYPE)) { preferenceMetadata.putString(METADATA_PREF_TYPE, nodeName); Loading Loading @@ -236,6 +245,10 @@ public class PreferenceXmlParserUtils { preferenceMetadata.putBoolean(METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE, isDynamicSummaryAllowed(preferenceAttributes)); } if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_APPEND) && hasPrefScreenFlag) { preferenceMetadata.putBoolean(METADATA_APPEND, isAppended(preferenceScreenAttributes)); } metadata.add(preferenceMetadata); preferenceAttributes.recycle(); Loading Loading @@ -325,7 +338,12 @@ public class PreferenceXmlParserUtils { false /* default */); } private static String getKeywords(TypedArray styleAttributes) { return styleAttributes.getString(R.styleable.Preference_keywords); private static String getKeywords(TypedArray styledAttributes) { return styledAttributes.getString(R.styleable.Preference_keywords); } private static boolean isAppended(TypedArray styledAttributes) { return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation, PREPEND_VALUE) == APPEND_VALUE; } }
src/com/android/settings/widget/RadioButtonPickerFragment.java +29 −2 Original line number Diff line number Diff line Loading @@ -22,10 +22,12 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import androidx.annotation.LayoutRes; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; Loading @@ -34,16 +36,23 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.PreferenceXmlParserUtils; import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag; import com.android.settingslib.widget.CandidateInfo; import java.io.IOException; import java.util.List; import java.util.Map; import org.xmlpull.v1.XmlPullParserException; public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements RadioButtonPreference.OnClickListener { @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting static final String EXTRA_FOR_WORK = "for_work"; private static final String TAG = "RadioButtonPckrFrgmt"; @VisibleForTesting boolean mAppendStaticPreferences = false; private final Map<String, CandidateInfo> mCandidates = new ArrayMap<>(); Loading @@ -69,6 +78,19 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { super.onCreatePreferences(savedInstanceState, rootKey); try { // Check if the xml specifies if static preferences should go on the top or bottom final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(getContext(), getPreferenceScreenResId(), MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND); mAppendStaticPreferences = metadata.get(0) .getBoolean(PreferenceXmlParserUtils.METADATA_APPEND); } catch (IOException e) { Log.e(TAG, "Error trying to open xml file", e); } catch (XmlPullParserException e) { Log.e(TAG, "Error parsing xml", e); } updateCandidates(); } Loading Loading @@ -142,7 +164,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr final String systemDefaultKey = getSystemDefaultKey(); final PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); if (!mAppendStaticPreferences) { addStaticPreferences(screen); } final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId(); if (shouldShowItemNone()) { Loading @@ -168,6 +192,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr } } mayCheckOnlyRadioButton(); if (mAppendStaticPreferences) { addStaticPreferences(screen); } } @VisibleForTesting Loading