diff options
author | Scott Main <smain@google.com> | 2012-03-09 19:10:40 -0800 |
---|---|---|
committer | Scott Main <smain@google.com> | 2012-07-25 13:52:46 -0700 |
commit | bbb3f41e26ac5a996913907dc63786146132b4ce (patch) | |
tree | 44c3c366cedcebb8702501b6b094672db684153c /docs | |
parent | 156671ef9a6581b6790bb17bfda8a9efcf9f0693 (diff) | |
download | frameworks_base-bbb3f41e26ac5a996913907dc63786146132b4ce.zip frameworks_base-bbb3f41e26ac5a996913907dc63786146132b4ce.tar.gz frameworks_base-bbb3f41e26ac5a996913907dc63786146132b4ce.tar.bz2 |
docs: add Settings dev guide;
a few changes to javadocs
Change-Id: I2d671aafe91e4c6e224e2a556a60dce9f93f11ae
Diffstat (limited to 'docs')
-rw-r--r-- | docs/html/guide/components/fragments.jd | 6 | ||||
-rw-r--r-- | docs/html/guide/guide_toc.cs | 3 | ||||
-rw-r--r-- | docs/html/guide/topics/ui/settings.jd | 1171 | ||||
-rw-r--r-- | docs/html/images/ui/settings/settings-headers-handset.png | bin | 0 -> 57277 bytes | |||
-rw-r--r-- | docs/html/images/ui/settings/settings-headers-tablet.png | bin | 0 -> 52567 bytes | |||
-rw-r--r-- | docs/html/images/ui/settings/settings-subscreen.png | bin | 0 -> 49541 bytes | |||
-rw-r--r-- | docs/html/images/ui/settings/settings-titles.png | bin | 0 -> 66806 bytes | |||
-rw-r--r-- | docs/html/images/ui/settings/settings.png | bin | 0 -> 96681 bytes |
8 files changed, 1180 insertions, 0 deletions
diff --git a/docs/html/guide/components/fragments.jd b/docs/html/guide/components/fragments.jd index 938e0ab..4f62033 100644 --- a/docs/html/guide/components/fragments.jd +++ b/docs/html/guide/components/fragments.jd @@ -709,6 +709,12 @@ href="{@docRoot}guide/components/activities.html#Lifecycle">managing the activit lifecycle</a> also apply to fragments. What you also need to understand, though, is how the life of the activity affects the life of the fragment.</p> +<p class="caution"><strong>Caution:</strong> If you need a {@link android.content.Context} object +within your {@link android.app.Fragment}, you can call {@link android.app.Fragment#getActivity()}. +However, be careful to call {@link android.app.Fragment#getActivity()} only when the fragment is +attached to an activity. When the fragment is not yet attached, or was detached during the end of +its lifecycle, {@link android.app.Fragment#getActivity()} will return null.</p> + <h3 id="CoordinatingWithActivity">Coordinating with the activity lifecycle</h3> diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 94b9773..9465f18 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -197,6 +197,9 @@ <li><a href="<?cs var:toroot ?>guide/topics/ui/actionbar.html"> <span class="en">Action Bar</span> </a></li> + <li><a href="<?cs var:toroot ?>guide/topics/ui/settings.html"> + <span class="en">Settings</span> + </a></li> <li class="nav-section"> <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/ui/notifiers/index.html"> <span class="en">Notifications</span> diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd new file mode 100644 index 0000000..fd3b684 --- /dev/null +++ b/docs/html/guide/topics/ui/settings.jd @@ -0,0 +1,1171 @@ +page.title=Settings +@jd:body + + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> +<ol> + <li><a href="#Overview">Overview</a> + <ol> + <li><a href="#SettingTypes">Preferences</a></li> + </ol> + </li> + <li><a href="#DefiningPrefs">Defining Preferences in XML</a> + <ol> + <li><a href="#Groups">Creating setting groups</a></li> + <li><a href="#Intents">Using intents</a></li> + </ol> + </li> + <li><a href="#Activity">Creating a Preference Activity</a></li> + <li><a href="#Fragment">Using Preference Fragments</a></li> + <li><a href="#Defaults">Setting Default Values</a></li> + <li><a href="#PreferenceHeaders">Using Preference Headers</a> + <ol> + <li><a href="#CreateHeaders">Creating the headers file</a></li> + <li><a href="#DisplayHeaders">Displaying the headers</a></li> + <li><a href="#BackCompatHeaders">Supporting older versions with preference headers</a></li> + </ol> + </li> + <li><a href="#ReadingPrefs">Reading Preferences</a> + <ol> + <li><a href="#Listening">Listening for preference changes</a></li> + </ol> + </li> + <li><a href="#NetworkUsage">Managing Network Usage</a></li> + <li><a href="#Custom">Building a Custom Preference</a> + <ol> + <li><a href="#CustomSelected">Specifying the user interface</a></li> + <li><a href="#CustomSave">Saving the setting's value</a></li> + <li><a href="#CustomInitialize">Initializing the current value</a></li> + <li><a href="#CustomDefault">Providing a default value</a></li> + <li><a href="#CustomSaveState">Saving and restoring the Preference's state</a></li> + </ol> + </li> +</ol> + +<h2>Key classes</h2> +<ol> + <li>{@link android.preference.Preference}</li> + <li>{@link android.preference.PreferenceActivity}</li> + <li>{@link android.preference.PreferenceFragment}</li> +</ol> + + +<h2>See also</h2> +<ol> + <li><a +href="{@docRoot}design/patterns/settings.html">Settings design guide</a></li> +</ol> +</div> +</div> + + + + +<p>Applications often include settings that allow users to modify app features and behaviors. For +example, some apps allow users to specify whether notifications are enabled or specify how often the +application syncs data with the cloud.</p> + +<p>If you want to provide settings for your app, you should use +Android's {@link android.preference.Preference} APIs to build an interface that's consistent with +the user experience in other Android apps (including the system settings). This document describes +how to build your app settings using {@link android.preference.Preference} APIs.</p> + +<div class="note design"> +<p><strong>Settings Design</strong></p> + <p>For information about how to design your settings, read the <a +href="{@docRoot}design/patterns/settings.html">Settings</a> design guide.</p> +</div> + + +<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" /> +<p class="img-caption"><strong>Figure 1.</strong> Screenshots from the Android Messaging app's +settings. Selecting an item defined by a {@link android.preference.Preference} +opens an interface to change the setting.</p> + + + + +<h2 id="Overview">Overview</h2> + +<p>Instead of using {@link android.view.View} objects to build the user interface, settings are +built using various subclasses of the {@link android.preference.Preference} class that you +declare in an XML file.</p> + +<p>A {@link android.preference.Preference} object is the building block for a single +setting. Each {@link android.preference.Preference} appears as an item in a list and provides the +appropriate UI for users to modify the setting. For example, a {@link +android.preference.CheckBoxPreference} creates a list item that shows a checkbox, and a {@link +android.preference.ListPreference} creates an item that opens a dialog with a list of choices.</p> + +<p>Each {@link android.preference.Preference} you add has a corresponding key-value pair that +the system uses to save the setting in a default {@link android.content.SharedPreferences} +file for your app's settings. When the user changes a setting, the system updates the corresponding +value in the {@link android.content.SharedPreferences} file for you. The only time you should +directly interact with the associated {@link android.content.SharedPreferences} file is when you +need to read the value in order to determine your app's behavior based on the user's setting.</p> + +<p>The value saved in {@link android.content.SharedPreferences} for each setting can be one of the +following data types:</p> + +<ul> + <li>Boolean</li> + <li>Float</li> + <li>Int</li> + <li>Long</li> + <li>String</li> + <li>String {@link java.util.Set}</li> +</ul> + +<p>Because your app's settings UI is built using {@link android.preference.Preference} objects +instead of +{@link android.view.View} objects, you need to use a specialized {@link android.app.Activity} or +{@link android.app.Fragment} subclass to display the list settings:</p> + +<ul> + <li>If your app supports versions of Android older than 3.0 (API level 10 and lower), you must +build the activity as an extension of the {@link android.preference.PreferenceActivity} class.</li> + <li>On Android 3.0 and later, you should instead use a traditional {@link android.app.Activity} +that hosts a {@link android.preference.PreferenceFragment} that displays your app settings. +However, you can also use {@link android.preference.PreferenceActivity} to create a two-pane layout +for large screens when you have multiple groups of settings.</li> +</ul> + +<p>How to set up your {@link android.preference.PreferenceActivity} and instances of {@link +android.preference.PreferenceFragment} is discussed in the sections about <a +href="#Activity">Creating a Preference Activity</a> and <a href="#Fragment">Using +Preference Fragments</a>.</p> + + +<h3 id="SettingTypes">Preferences</h3> + +<p>Every setting for your app is represented by a specific subclass of the {@link +android.preference.Preference} class. Each subclass includes a set of core properties that allow you +to specify things such as a title for the setting and the default value. Each subclass also provides +its own specialized properties and user interface. For instance, figure 1 shows a screenshot from +the Messaging app's settings. Each list item in the settings screen is backed by a different {@link +android.preference.Preference} object.</p> + +<p>A few of the most common preferences are:</p> + +<dl> + <dt>{@link android.preference.CheckBoxPreference}</dt> + <dd>Shows an item with a checkbox for a setting that is either enabled or disabled. The saved +value is a boolean (<code>true</code> if it's checked).</dd> + + <dt>{@link android.preference.ListPreference}</dt> + <dd>Opens a dialog with a list of radio buttons. The saved value +can be any one of the supported value types (listed above).</dd> + + <dt>{@link android.preference.EditTextPreference}</dt> + <dd>Opens a dialog with an {@link android.widget.EditText} widget. The saved value is a {@link +java.lang.String}.</dd> +</dl> + +<p>See the {@link android.preference.Preference} class for a list of all other subclasses and their +corresponding properties.</p> + +<p>Of course, the built-in classes don't accommodate every need and your application might require +something more specialized. For example, the platform currently does not provide a {@link +android.preference.Preference} class for picking a number or a date. So you might need to define +your own {@link android.preference.Preference} subclass. For help doing so, see the section about <a +href="#Custom">Building a Custom Preference</a>.</p> + + + +<h2 id="DefiningPrefs">Defining Preferences in XML</h2> + +<p>Although you can instantiate new {@link android.preference.Preference} objects at runtime, you +should define your list of settings in XML with a hierarchy of {@link android.preference.Preference} +objects. Using an XML file to define your collection of settings is preferred because the file +provides an easy-to-read structure that's simple to update. Also, your app's settings are +generally pre-determined, although you can still modify the collection at runtime.</p> + +<p>Each {@link android.preference.Preference} subclass can be declared with an XML element that +matches the class name, such as {@code <CheckBoxPreference>}.</p> + +<p>You must save the XML file in the {@code res/xml/} directory. Although you can name the file +anything you want, it's traditionally named {@code preferences.xml}. You usually need only one file, +because branches in the hierarchy (that open their own list of settings) are declared using nested +instances of {@link android.preference.PreferenceScreen}.</p> + +<p class="note"><strong>Note:</strong> If you want to create a multi-pane layout for your +settings, then you need separate XML files for each fragment.</p> + +<p>The root node for the XML file must be a {@link android.preference.PreferenceScreen +<PreferenceScreen>} element. Within this element is where you add each {@link +android.preference.Preference}. Each child you add within the +{@link android.preference.PreferenceScreen <PreferenceScreen>} element appears as a single +item in the list of settings.</p> + +<p>For example:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <CheckBoxPreference + android:key="pref_sync" + android:title="@string/pref_sync" + android:summary="@string/pref_sync_summ" + android:defaultValue="true" /> + <ListPreference + android:dependency="pref_sync" + android:key="pref_syncConnectionType" + android:title="@string/pref_syncConnectionType" + android:dialogTitle="@string/pref_syncConnectionType" + android:entries="@array/pref_syncConnectionTypes_entries" + android:entryValues="@array/pref_syncConnectionTypes_values" + android:defaultValue="@string/pref_syncConnectionTypes_default" > +</PreferenceScreen> +</pre> + +<p>In this example, there's a {@link android.preference.CheckBoxPreference} and a {@link +android.preference.ListPreference}. Both items include the following three attributes:</p> + +<dl> + <dt>{@code android:key}</dt> + <dd>This attribute is required for preferences that persist a data value. It specifies the unique +key (a string) the system uses when saving this setting's value in the {@link +android.content.SharedPreferences}. + <p>The only instances in which this attribute is <em>not required</em> is when the preference is a +{@link android.preference.PreferenceCategory} or {@link android.preference.PreferenceScreen}, or the +preference specifies an {@link android.content.Intent} to invoke (with an <a +href="#Intents">{@code <intent>}</a> element) or a {@link android.app.Fragment} to display (with an <a +href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code +android:fragment}</a> attribute).</p> + </dd> + <dt>{@code android:title}</dt> + <dd>This provides a user-visible name for the setting.</dd> + <dt>{@code android:defaultValue}</dt> + <dd>This specifies the initial value that the system should set in the {@link +android.content.SharedPreferences} file. You should supply a default value for all +settings.</dd> +</dl> + +<p>For information about all other supported attributes, see the {@link +android.preference.Preference} (and respective subclass) documentation.</p> + + +<div class="figure" style="width:300px"> + <img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" /> + <p class="img-caption"><strong>Figure 2.</strong> Setting categories + with titles. <br/><b>1.</b> The category is specified by the {@link +android.preference.PreferenceCategory <PreferenceCategory>} element. <br/><b>2.</b> The title is +specified with the {@code android:title} attribute.</p> +</div> + + +<p>When your list of settings exceeds about 10 items, you might want to add titles to +define groups of settings or display those groups in a +separate screen. These options are described in the following sections.</p> + + +<h3 id="Groups">Creating setting groups</h3> + +<p>If you present a list of 10 or more settings, users +may have difficulty scanning, comprehending, and processing them. You can remedy this by +dividing some or all of the settings into groups, effectively turning one long list into multiple +shorter lists. A group of related settings can be presented in one of two ways:</p> + +<ul> + <li><a href="#Titles">Using titles</a></li> + <li><a href="#Subscreens">Using subscreens</a></li> +</ul> + +<p>You can use one or both of these grouping techniques to organize your app's settings. When +deciding which to use and how to divide your settings, you should follow the guidelines in Android +Design's <a href="{@docRoot}design/patterns/settings.html">Settings</a> guide.</p> + + +<h4 id="Titles">Using titles</h4> + +<p>If you want to provide dividers with headings between groups of settings (as shown in figure 2), +place each group of {@link android.preference.Preference} objects inside a {@link +android.preference.PreferenceCategory}.</p> + +<p>For example:</p> + +<pre> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <PreferenceCategory + android:title="@string/pref_sms_storage_title" + android:key="pref_key_storage_settings"> + <CheckBoxPreference + android:key="pref_key_auto_delete" + android:summary="@string/pref_summary_auto_delete" + android:title="@string/pref_title_auto_delete" + android:defaultValue="false"... /> + <Preference + android:key="pref_key_sms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_sms_delete"... /> + <Preference + android:key="pref_key_mms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_mms_delete" ... /> + </PreferenceCategory> + ... +</PreferenceScreen> +</pre> + + +<h4 id="Subscreens">Using subscreens</h4> + +<p>If you want to place groups of settings into a subscreen (as shown in figure 3), place the group +of {@link android.preference.Preference} objects inside a {@link +android.preference.PreferenceScreen}.</p> + +<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" /> +<p class="img-caption"><strong>Figure 3.</strong> Setting subscreens. The {@code +<PreferenceScreen>} element +creates an item that, when selected, opens a separate list to display the nested settings.</p> + +<p>For example:</p> + +<pre> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- opens a subscreen of settings --> + <PreferenceScreen + android:key="button_voicemail_category_key" + android:title="@string/voicemail" + android:persistent="false"> + <ListPreference + android:key="button_voicemail_provider_key" + android:title="@string/voicemail_provider" ... /> + <!-- opens another nested subscreen --> + <PreferenceScreen + android:key="button_voicemail_setting_key" + android:title="@string/voicemail_settings" + android:persistent="false"> + ... + </PreferenceScreen> + <RingtonePreference + android:key="button_voicemail_ringtone_key" + android:title="@string/voicemail_ringtone_title" + android:ringtoneType="notification" ... /> + ... + </PreferenceScreen> + ... +</PreferenceScreen> +</pre> + + +<h3 id="Intents">Using intents</h3> + +<p>In some cases, you might want a preference item to open a different activity instead of a +settings screen, such as a web browser to view a web page. To invoke an {@link +android.content.Intent} when the user selects a preference item, add an {@code <intent>} +element as a child of the corresponding {@code <Preference>} element.</p> + +<p>For example, here's how you can use a preference item to open a web page:</p> + +<pre> +<Preference android:title="@string/prefs_web_page" > + <intent android:action="android.intent.action.VIEW" + android:data="http://www.example.com" /> +</Preference> +</pre> + +<p>You can create both implicit and explicit intents using the following attributes:</p> + +<dl> + <dt>{@code android:action}</dt> + <dd>The action to assign, as per the {@link android.content.Intent#setAction setAction()} +method.</dd> + <dt>{@code android:data}</dt> + <dd>The data to assign, as per the {@link android.content.Intent#setData setData()} method.</dd> + <dt>{@code android:mimeType}</dt> + <dd>The MIME type to assign, as per the {@link android.content.Intent#setType setType()} +method.</dd> + <dt>{@code android:targetClass}</dt> + <dd>The class part of the component name, as per the {@link android.content.Intent#setComponent +setComponent()} method.</dd> + <dt>{@code android:targetPackage}</dt> + <dd>The package part of the component name, as per the {@link +android.content.Intent#setComponent setComponent()} method.</dd> +</dl> + + + +<h2 id="Activity">Creating a Preference Activity</h2> + +<p>To display your settings in an activity, extend the {@link +android.preference.PreferenceActivity} class. This is an extension of the traditional {@link +android.app.Activity} class that displays a list of settings based on a hierarchy of {@link +android.preference.Preference} objects. The {@link android.preference.PreferenceActivity} +automatically persists the settings associated with each {@link +android.preference.Preference} when the user makes a change.</p> + +<p class="note"><strong>Note:</strong> If you're developing your application for Android 3.0 and +higher, you should instead use {@link android.preference.PreferenceFragment}. Go to the next +section about <a href="#Fragment">Using Preference Fragments</a>.</p> + +<p>The most important thing to remember is that you do not load a layout of views during the {@link +android.preference.PreferenceActivity#onCreate onCreate()} callback. Instead, you call {@link +android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} to +add the preferences you've declared in an XML file to the activity. For example, here's the bare +minimum code required for a functional {@link android.preference.PreferenceActivity}:</p> + +<pre> +public class SettingsActivity extends PreferenceActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } +} +</pre> + +<p>This is actually enough code for some apps, because as soon as the user modifies a preference, +the system saves the changes to a default {@link android.content.SharedPreferences} file that your +other application components can read when you need to check the user's settings. Many apps, +however, require a little more code in order to listen for changes that occur to the preferences. +For information about listening to changes in the {@link android.content.SharedPreferences} file, +see the section about <a href="#ReadingPrefs">Reading Preferences</a>.</p> + + + + +<h2 id="Fragment">Using Preference Fragments</h2> + +<p>If you're developing for Android 3.0 (API level 11) and higher, you should use a {@link +android.preference.PreferenceFragment} to display your list of {@link android.preference.Preference} +objects. You can add a {@link android.preference.PreferenceFragment} to any activity—you don't +need to use {@link android.preference.PreferenceActivity}.</p> + +<p><a href="{@docRoot}guide/components/fragments.html">Fragments</a> provide a more +flexible architecture for your application, compared to using activities alone, no matter what kind +of activity you're building. As such, we suggest you use {@link +android.preference.PreferenceFragment} to control the display of your settings instead of {@link +android.preference.PreferenceActivity} when possible.</p> + +<p>Your implementation of {@link android.preference.PreferenceFragment} can be as simple as +defining the {@link android.preference.PreferenceFragment#onCreate onCreate()} method to load a +preferences file with {@link android.preference.PreferenceFragment#addPreferencesFromResource +addPreferencesFromResource()}. For example:</p> + +<pre> +public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.preferences); + } + ... +} +</pre> + +<p>You can then add this fragment to an {@link android.app.Activity} just as you would for any other +{@link android.app.Fragment}. For example:</p> + +<pre> +public class SettingsActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction() + .replace(android.R.id.content, new SettingsFragment()) + .commit(); + } +} +</pre> + +<p class="note"><strong>Note:</strong> A {@link android.preference.PreferenceFragment} doesn't have +a its own {@link android.content.Context} object. If you need a {@link android.content.Context} +object, you can call {@link android.app.Fragment#getActivity()}. However, be careful to call +{@link android.app.Fragment#getActivity()} only when the fragment is attached to an activity. When +the fragment is not yet attached, or was detached during the end of its lifecycle, {@link +android.app.Fragment#getActivity()} will return null.</p> + + +<h2 id="Defaults">Setting Default Values</h2> + +<p>The preferences you create probably define some important behaviors for your application, so it's +necessary that you initialize the associated {@link android.content.SharedPreferences} file with +default values for each {@link android.preference.Preference} when the user first opens your +application.</p> + +<p>The first thing you must do is specify a default value for each {@link +android.preference.Preference} +object in your XML file using the {@code android:defaultValue} attribute. The value can be any data +type that is appropriate for the corresponding {@link android.preference.Preference} object. For +example:</p> + +<pre> +<!-- default value is a boolean --> +<CheckBoxPreference + android:defaultValue="true" + ... /> + +<!-- default value is a string --> +<ListPreference + android:defaultValue="@string/pref_syncConnectionTypes_default" + ... /> +</pre> + +<p>Then, from the {@link android.app.Activity#onCreate onCreate()} method in your application's main +activity—and in any other activity through which the user may enter your application for the +first time—call {@link android.preference.PreferenceManager#setDefaultValues +setDefaultValues()}:</p> + +<pre> +PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false); +</pre> + +<p>Calling this during {@link android.app.Activity#onCreate onCreate()} ensures that your +application is properly initialized with default settings, which your application might need to +read in order to determine some behaviors (such as whether to download data while on a +cellular network).</p> + +<p>This method takes three arguments:</p> +<ul> + <li>Your application {@link android.content.Context}.</li> + <li>The resource ID for the preference XML file for which you want to set the default values.</li> + <li>A boolean indicating whether the default values should be set more than once. +<p>When <code>false</code>, the system sets the default values only if this method has never been +called in the past (or the {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} +in the default value shared preferences file is false).</p></li> +</ul> + +<p>As long as you set the third argument to <code>false</code>, you can safely call this method +every time your activity starts without overriding the user's saved preferences by resetting them to +the defaults. However, if you set it to <code>true</code>, you will override any previous +values with the defaults.</p> + + + +<h2 id="PreferenceHeaders">Using Preference Headers</h2> + +<p>In rare cases, you might want to design your settings such that the first screen +displays only a list of <a href="#Subscreens">subscreens</a> (such as in the system Settings app, +as shown in figures 4 and 5). When you're developing such a design for Android 3.0 and higher, you +should use a new "headers" feature in Android 3.0, instead of building subscreens with nested +{@link android.preference.PreferenceScreen} elements.</p> + +<p>To build your settings with headers, you need to:</p> +<ol> + <li>Separate each group of settings into separate instances of {@link +android.preference.PreferenceFragment}. That is, each group of settings needs a separate XML +file.</li> + <li>Create an XML headers file that lists each settings group and declares which fragment +contains the corresponding list of settings.</li> + <li>Extend the {@link android.preference.PreferenceActivity} class to host your settings.</li> + <li>Implement the {@link +android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} callback to specify the +headers file.</li> +</ol> + +<p>A great benefit to using this design is that {@link android.preference.PreferenceActivity} +automatically presents the two-pane layout shown in figure 4 when running on large screens.</p> + +<p>Even if your application supports versions of Android older than 3.0, you can build your +application to use {@link android.preference.PreferenceFragment} for a two-pane presentation on +newer devices while still supporting a traditional multi-screen hierarchy on older +devices (see the section about <a href="#BackCompatHeaders">Supporting older versions with +preference headers</a>).</p> + +<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" /> +<p class="img-caption"><strong>Figure 4.</strong> Two-pane layout with headers. <br/><b>1.</b> The +headers are defined with an XML headers file. <br/><b>2.</b> Each group of settings is defined by a +{@link android.preference.PreferenceFragment} that's specified by a {@code <header>} element in +the headers file.</p> + +<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" /> +<p class="img-caption"><strong>Figure 5.</strong> A handset device with setting headers. When an +item is selected, the associated {@link android.preference.PreferenceFragment} replaces the +headers.</p> + + +<h3 id="CreateHeaders" style="clear:left">Creating the headers file</h3> + +<p>Each group of settings in your list of headers is specified by a single {@code <header>} +element inside a root {@code <preference-headers>} element. For example:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <!-- key/value pairs can be included as arguments for the fragment. --> + <extra android:name="someKey" android:value="someHeaderValue" /> + </header> +</preference-headers> +</pre> + +<p>With the {@code android:fragment} attribute, each header declares an instance of {@link +android.preference.PreferenceFragment} that should open when the user selects the header.</p> + +<p>The {@code <extras>} element allows you to pass key-value pairs to the fragment in a {@link +android.os.Bundle}. The fragment can retrieve the arguments by calling {@link +android.app.Fragment#getArguments()}. You might pass arguments to the fragment for a variety of +reasons, but one good reason is to reuse the same subclass of {@link +android.preference.PreferenceFragment} for each group and use the argument to specify which +preferences XML file the fragment should load.</p> + +<p>For example, here's a fragment that can be reused for multiple settings groups, when each +header defines an {@code <extra>} argument with the {@code "settings"} key:</p> + +<pre> +public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String settings = getArguments().getString("settings"); + if ("notifications".equals(settings)) { + addPreferencesFromResource(R.xml.settings_wifi); + } else if ("sync".equals(settings)) { + addPreferencesFromResource(R.xml.settings_sync); + } + } +} +</pre> + + + +<h3 id="DisplayHeaders">Displaying the headers</h3> + +<p>To display the preference headers, you must implement the {@link +android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} callback method and call +{@link android.preference.PreferenceActivity#loadHeadersFromResource +loadHeadersFromResource()}. For example:</p> + +<pre> +public class SettingsActivity extends PreferenceActivity { + @Override + public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); + } +} +</pre> + +<p>When the user selects an item from the list of headers, the system opens the associated {@link +android.preference.PreferenceFragment}.</p> + +<p class="note"><strong>Note:</strong> When using preference headers, your subclass of {@link +android.preference.PreferenceActivity} doesn't need to implement the {@link +android.preference.PreferenceActivity#onCreate onCreate()} method, because the only required +task for the activity is to load the headers.</p> + + +<h3 id="BackCompatHeaders">Supporting older versions with preference headers</h3> + +<p>If your application supports versions of Android older than 3.0, you can still use headers to +provide a two-pane layout when running on Android 3.0 and higher. All you need to do is create an +additional preferences XML file that uses basic {@link android.preference.Preference +<Preference>} elements that behave like the header items (to be used by the older Android +versions).</p> + +<p>Instead of opening a new {@link android.preference.PreferenceScreen}, however, each of the {@link +android.preference.Preference <Preference>} elements sends an {@link android.content.Intent} to +the {@link android.preference.PreferenceActivity} that specifies which preference XML file to +load.</p> + +<p>For example, here's an XML file for preference headers that is used on Android 3.0 +and higher ({@code res/xml/preference_headers.xml}):</p> + +<pre> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" /> +</preference-headers> +</pre> + +<p>And here is a preference file that provides the same headers for versions older than +Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):</p> + +<pre> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <Preference + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_ONE" /> + </Preference> + <Preference + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_TWO" /> + </Preference> +</PreferenceScreen> +</pre> + +<p>Because support for {@code <preference-headers>} was added in Android 3.0, the system calls +{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} in your {@link +android.preference.PreferenceActivity} only when running on Androd 3.0 or higher. In order to load +the "legacy" headers file ({@code preference_headers_legacy.xml}), you must check the Android +version and, if the version is older than Android 3.0 ({@link +android.os.Build.VERSION_CODES#HONEYCOMB}), call {@link +android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} to +load the legacy header file. For example:</p> + +<pre> +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ... + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} + +// Called only on Honeycomb and later +@Override +public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); +} +</pre> + +<p>The only thing left to do is handle the {@link android.content.Intent} that's passed into the +activity to identify which preference file to load. So retrieve the intent's action and compare it +to known action strings that you've used in the preference XML's {@code <intent>} tags:</p> + +<pre> +final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE"; +... + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String action = getIntent().getAction(); + if (action != null && action.equals(ACTION_PREFS_ONE)) { + addPreferencesFromResource(R.xml.preferences); + } + ... + + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} +</pre> + +<p>Beware that consecutive calls to {@link +android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} will +stack all the preferences in a single list, so be sure that it's only called once by chaining the +conditions with else-if statements.</p> + + + + + +<h2 id="ReadingPrefs">Reading Preferences</h2> + +<p>By default, all your app's preferences are saved to a file that's accessible from anywhere +within your application by calling the static method {@link +android.preference.PreferenceManager#getDefaultSharedPreferences +PreferenceManager.getDefaultSharedPreferences()}. This returns the {@link +android.content.SharedPreferences} object containing all the key-value pairs that are associated +with the {@link android.preference.Preference} objects used in your {@link +android.preference.PreferenceActivity}.</p> + +<p>For example, here's how you can read one of the preference values from any other activity in your +application:</p> + +<pre> +SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); +String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, ""); +</pre> + + + +<h3 id="Listening">Listening for preference changes</h3> + +<p>There are several reasons you might want to be notified as soon as the use changes one of the +preferences. In order to receive a callback when a change happens to any one of the preferences, +implement the {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener +SharedPreference.OnSharedPreferenceChangeListener} interface and register the listener for the +{@link android.content.SharedPreferences} object by calling {@link +android.content.SharedPreferences#registerOnSharedPreferenceChangeListener +registerOnSharedPreferenceChangeListener()}.</p> + +<p>The interface has only one callback method, {@link +android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged +onSharedPreferenceChanged()}, and you might find it easiest to implement the interface as a part of +your activity. For example:</p> + +<pre> +public class SettingsActivity extends PreferenceActivity + implements OnSharedPreferenceChangeListener { + public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType"; + ... + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(KEY_PREF_SYNC_CONN)) { + Preference connectionPref = findPreference(key); + // Set summary to be the user-description for the selected value + connectionPref.setSummary(sharedPreferences.getString(key, "")); + } + } +} +</pre> + +<p>In this example, the method checks whether the changed setting is for a known preference key. It +calls {@link android.preference.PreferenceActivity#findPreference findPreference()} to get the +{@link android.preference.Preference} object that was changed so it can modify the item's +summary to be a description of the user's selection. That is, when the setting is a {@link +android.preference.ListPreference} or other multiple choice setting, you should call {@link +android.preference.Preference#setSummary setSummary()} when the setting changes to display the +current status (such as the Sleep setting shown in figure 5).</p> + +<p class="note"><strong>Note:</strong> As described in the Android Design document about <a +href="{@docRoot}design/patterns/settings.html">Settings</a>, we recommend that you update the +summary for a {@link android.preference.ListPreference} each time the user changes the preference in +order to describe the current setting.</p> + +<p>For proper lifecycle management in the activity, we recommend that you register and unregister +your {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} during the {@link +android.app.Activity#onResume} and {@link android.app.Activity#onPause} callbacks, respectively:</p> + +<pre> +@Override +protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); +} + +@Override +protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); +} +</pre> + + + +<h2 id="NetworkUsage">Managing Network Usage</h2> + + +<p>Beginning with Android 4.0, the system's Settings application allows users to see how much +network data their applications are using while in the foreground and background. Users can then +disable the use of background data for individual apps. In order to avoid users disabling your app's +access to data from the background, you should use the data connection efficiently and allow +users to refine your app's data usage through your application settings.<p> + +<p>For example, you might allow the user to control how often your app syncs data, whether your app +performs uploads/downloads only when on Wi-Fi, whether your app uses data while roaming, etc. With +these controls available to them, users are much less likely to disable your app's access to data +when they approach the limits they set in the system Settings, because they can instead precisely +control how much data your app uses.</p> + +<p>Once you've added the necessary preferences in your {@link android.preference.PreferenceActivity} +to control your app's data habits, you should add an intent filter for {@link +android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} in your manifest file. For example:</p> + +<pre> +<activity android:name="SettingsActivity" ... > + <intent-filter> + <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> +</activity> +</pre> + +<p>This intent filter indicates to the system that this is the activity that controls your +application's data usage. Thus, when the user inspects how much data your app is using from the +system's Settings app, a <em>View application settings</em> button is available that launches your +{@link android.preference.PreferenceActivity} so the user can refine how much data your app +uses.</p> + + + + + + + +<h2 id="Custom">Building a Custom Preference</h2> + +<p>The Android framework includes a variety of {@link android.preference.Preference} subclasses that +allow you to build a UI for several different types of settings. +However, you might discover a setting you need for which there’s no built-in solution, such as a +number picker or date picker. In such a case, you’ll need to create a custom preference by extending +the {@link android.preference.Preference} class or one of the other subclasses.</p> + +<p>When you extend the {@link android.preference.Preference} class, there are a few important +things you need to do:</p> + +<ul> + <li>Specify the user interface that appears when the user selects the settings.</li> + <li>Save the setting's value when appropriate.</li> + <li>Initialize the {@link android.preference.Preference} with the current (or default) value +when it comes into view.</li> + <li>Provide the default value when requested by the system.</li> + <li>If the {@link android.preference.Preference} provides its own UI (such as a dialog), save +and restore the state to handle lifecycle changes (such as when the user rotates the screen).</li> +</ul> + +<p>The following sections describe how to accomplish each of these tasks.</p> + + + +<h3 id="CustomSelected">Specifying the user interface</h3> + + <p>If you directly extend the {@link android.preference.Preference} class, you need to implement +{@link android.preference.Preference#onClick()} to define the action that occurs when the user +selects the item. However, most custom settings extend {@link android.preference.DialogPreference} to +show a dialog, which simplifies the procedure. When you extend {@link +android.preference.DialogPreference}, you must call {@link +android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} during in the +class constructor to specify the layout for the dialog.</p> + + <p>For example, here's the constructor for a custom {@link +android.preference.DialogPreference} that declares the layout and specifies the text for the +default positive and negative dialog buttons:</p> + +<pre> +public class NumberPickerPreference extends DialogPreference { + public NumberPickerPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setDialogLayoutResource(R.layout.numberpicker_dialog); + setPositiveButtonText(android.R.string.ok); + setNegativeButtonText(android.R.string.cancel); + + setDialogIcon(null); + } + ... +} +</pre> + + + +<h3 id="CustomSave">Saving the setting's value</h3> + +<p>You can save a value for the setting at any time by calling one of the {@link +android.preference.Preference} class's {@code persist*()} methods, such as {@link +android.preference.Preference#persistInt persistInt()} if the setting's value is an integer or +{@link android.preference.Preference#persistBoolean persistBoolean()} to save a boolean.</p> + +<p class="note"><strong>Note:</strong> Each {@link android.preference.Preference} can save only one +data type, so you must use the {@code persist*()} method appropriate for the data type used by your +custom {@link android.preference.Preference}.</p> + +<p>When you choose to persist the setting can depend on which {@link +android.preference.Preference} class you extend. If you extend {@link +android.preference.DialogPreference}, then you should persist the value only when the dialog +closes due to a positive result (the user selects the "OK" button).</p> + +<p>When a {@link android.preference.DialogPreference} closes, the system calls the {@link +android.preference.DialogPreference#onDialogClosed onDialogClosed()} method. The method includes a +boolean argument that specifies whether the user result is "positive"—if the value is +<code>true</code>, then the user selected the positive button and you should save the new value. For +example:</p> + +<pre> +@Override +protected void onDialogClosed(boolean positiveResult) { + // When the user selects "OK", persist the new value + if (positiveResult) { + persistInt(mNewValue); + } +} +</pre> + +<p>In this example, <code>mNewValue</code> is a class member that holds the setting's current +value. Calling {@link android.preference.Preference#persistInt persistInt()} saves the value to +the {@link android.content.SharedPreferences} file (automatically using the key that's +specified in the XML file for this {@link android.preference.Preference}).</p> + + +<h3 id="CustomInitialize">Initializing the current value</h3> + +<p>When the system adds your {@link android.preference.Preference} to the screen, it +calls {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} to notify +you whether the setting has a persisted value. If there is no persisted value, this call provides +you the default value.</p> + +<p>The {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} method passes +a boolean, <code>restorePersistedValue</code>, to indicate whether a value has already been persisted +for the setting. If it is <code>true</code>, then you should retrieve the persisted value by calling +one of the {@link +android.preference.Preference} class's {@code getPersisted*()} methods, such as {@link +android.preference.Preference#getPersistedInt getPersistedInt()} for an integer value. You'll +usually want to retrieve the persisted value so you can properly update the UI to reflect the +previously saved value.</p> + +<p>If <code>restorePersistedValue</code> is <code>false</code>, then you +should use the default value that is passed in the second argument.</p> + +<pre> +@Override +protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { + if (restorePersistedValue) { + // Restore existing state + mCurrentValue = this.getPersistedInt(DEFAULT_VALUE); + } else { + // Set default state from the XML attribute + mCurrentValue = (Integer) defaultValue; + persistInt(mCurrentValue); + } +} +</pre> + +<p>Each {@code getPersisted*()} method takes an argument that specifies the +default value to use in case there is actually no persisted value or the key does not exist. In +the example above, a local constant is used to specify the default value in case {@link +android.preference.Preference#getPersistedInt getPersistedInt()} can't return a persisted value.</p> + +<p class="caution"><strong>Caution:</strong> You <strong>cannot</strong> use the +<code>defaultValue</code> as the default value in the {@code getPersisted*()} method, because +its value is always null when <code>restorePersistedValue</code> is <code>true</code>.</p> + + +<h3 id="CustomDefault">Providing a default value</h3> + +<p>If the instance of your {@link android.preference.Preference} class specifies a default value +(with the {@code android:defaultValue} attribute), then the +system calls {@link android.preference.Preference#onGetDefaultValue +onGetDefaultValue()} when it instantiates the object in order to retrieve the value. You must +implement this method in order for the system to save the default value in the {@link +android.content.SharedPreferences}. For example:</p> + +<pre> +@Override +protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInteger(index, DEFAULT_VALUE); +} +</pre> + +<p>The method arguments provide everything you need: the array of attributes and the index +position of the {@code android:defaultValue}, which you must retrieve. The reason you must +implement this method to extract the default value from the attribute is because you must specify +a local default value for the attribute in case the value is undefined.</p> + + + +<h3 id="CustomSaveState">Saving and restoring the Preference's state</h3> + +<p>Just like a {@link android.view.View} in a layout, your {@link android.preference.Preference} +subclass is responsible for saving and restoring its state in case the activity or fragment is +restarted (such as when the user rotates the screen). To properly save and +restore the state of your {@link android.preference.Preference} class, you must implement the +lifecycle callback methods {@link android.preference.Preference#onSaveInstanceState +onSaveInstanceState()} and {@link +android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.</p> + +<p>The state of your {@link android.preference.Preference} is defined by an object that implements +the {@link android.os.Parcelable} interface. The Android framework provides such an object for you +as a starting point to define your state object: the {@link +android.preference.Preference.BaseSavedState} class.</p> + +<p>To define how your {@link android.preference.Preference} class saves its state, you should +extend the {@link android.preference.Preference.BaseSavedState} class. You need to override just + a few methods and define the {@link android.preference.Preference.BaseSavedState#CREATOR} +object.</p> + +<p>For most apps, you can copy the following implementation and simply change the lines that +handle the {@code value} if your {@link android.preference.Preference} subclass saves a data +type other than an integer.</p> + +<pre> +private static class SavedState extends BaseSavedState { + // Member that holds the setting's value + // Change this data type to match the type saved by your Preference + int value; + + public SavedState(Parcelable superState) { + super(superState); + } + + public SavedState(Parcel source) { + super(source); + // Get the current preference's value + value = source.readInt(); // Change this to read the appropriate data type + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + // Write the preference's value + dest.writeInt(value); // Change this to write the appropriate data type + } + + // Standard creator object using an instance of this class + public static final Parcelable.Creator<SavedState> CREATOR = + new Parcelable.Creator<SavedState>() { + + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; +} +</pre> + +<p>With the above implementation of {@link android.preference.Preference.BaseSavedState} added +to your app (usually as a subclass of your {@link android.preference.Preference} subclass), you +then need to implement the {@link android.preference.Preference#onSaveInstanceState +onSaveInstanceState()} and {@link +android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} methods for your +{@link android.preference.Preference} subclass.</p> + +<p>For example:</p> + +<pre> +@Override +protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + // Check whether this Preference is persistent (continually saved) + if (isPersistent()) { + // No need to save instance state since it's persistent, use superclass state + return superState; + } + + // Create instance of custom BaseSavedState + final SavedState myState = new SavedState(superState); + // Set the state's value with the class member that holds current setting value + myState.value = mNewValue; + return myState; +} + +@Override +protected void onRestoreInstanceState(Parcelable state) { + // Check whether we saved the state in onSaveInstanceState + if (state == null || !state.getClass().equals(SavedState.class)) { + // Didn't save the state, so call superclass + super.onRestoreInstanceState(state); + return; + } + + // Cast state to custom BaseSavedState and pass to superclass + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + + // Set this Preference's widget to reflect the restored state + mNumberPicker.setValue(myState.value); +} +</pre> + diff --git a/docs/html/images/ui/settings/settings-headers-handset.png b/docs/html/images/ui/settings/settings-headers-handset.png Binary files differnew file mode 100644 index 0000000..d04ad17 --- /dev/null +++ b/docs/html/images/ui/settings/settings-headers-handset.png diff --git a/docs/html/images/ui/settings/settings-headers-tablet.png b/docs/html/images/ui/settings/settings-headers-tablet.png Binary files differnew file mode 100644 index 0000000..d0da5f2 --- /dev/null +++ b/docs/html/images/ui/settings/settings-headers-tablet.png diff --git a/docs/html/images/ui/settings/settings-subscreen.png b/docs/html/images/ui/settings/settings-subscreen.png Binary files differnew file mode 100644 index 0000000..17de231 --- /dev/null +++ b/docs/html/images/ui/settings/settings-subscreen.png diff --git a/docs/html/images/ui/settings/settings-titles.png b/docs/html/images/ui/settings/settings-titles.png Binary files differnew file mode 100644 index 0000000..df4e1b4 --- /dev/null +++ b/docs/html/images/ui/settings/settings-titles.png diff --git a/docs/html/images/ui/settings/settings.png b/docs/html/images/ui/settings/settings.png Binary files differnew file mode 100644 index 0000000..db9976c --- /dev/null +++ b/docs/html/images/ui/settings/settings.png |