diff options
| -rw-r--r-- | api/current.xml | 180 | ||||
| -rw-r--r-- | core/java/android/app/Fragment.java | 23 | ||||
| -rw-r--r-- | core/java/android/os/Build.java | 11 | ||||
| -rw-r--r-- | core/java/android/preference/PreferenceActivity.java | 522 | ||||
| -rw-r--r-- | core/java/android/preference/PreferenceFragment.java | 30 | ||||
| -rw-r--r-- | core/java/android/widget/ArrayAdapter.java | 6 | ||||
| -rw-r--r-- | core/res/res/layout/preference_list_content.xml | 28 | ||||
| -rw-r--r-- | core/res/res/layout/preference_list_item.xml | 61 | ||||
| -rwxr-xr-x | core/res/res/values/attrs.xml | 15 | ||||
| -rw-r--r-- | core/res/res/values/public.xml | 1 |
10 files changed, 767 insertions, 110 deletions
diff --git a/api/current.xml b/api/current.xml index b0aaf41..859175e 100644 --- a/api/current.xml +++ b/api/current.xml @@ -4299,6 +4299,17 @@ visibility="public" > </field> +<field name="fragment" + type="int" + transient="false" + volatile="false" + value="16843557" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="freezesText" type="int" transient="false" @@ -27640,6 +27651,33 @@ visibility="public" > </method> +<method name="instantiate" + return="android.app.Fragment" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="fname" type="java.lang.String"> +</parameter> +<exception name="ClassNotFoundException" type="java.lang.ClassNotFoundException"> +</exception> +<exception name="IllegalAccessException" type="java.lang.IllegalAccessException"> +</exception> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> +<exception name="InstantiationException" type="java.lang.InstantiationException"> +</exception> +<exception name="InvocationTargetException" type="java.lang.reflect.InvocationTargetException"> +</exception> +<exception name="NoSuchMethodException" type="java.lang.NoSuchMethodException"> +</exception> +</method> <method name="isAdded" return="boolean" abstract="false" @@ -124117,6 +124155,17 @@ visibility="public" > </field> +<field name="HONEYCOMB" + type="int" + transient="false" + volatile="false" + value="10000" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="Bundle" extends="java.lang.Object" @@ -134276,7 +134325,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="intent" type="android.content.Intent"> @@ -134289,7 +134338,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="preferencesResId" type="int"> @@ -134302,7 +134351,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="key" type="java.lang.CharSequence"> @@ -134315,7 +134364,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -134326,11 +134375,65 @@ synchronized="false" static="false" final="false" + deprecated="deprecated" + visibility="public" +> +</method> +<method name="loadHeadersFromResource" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" deprecated="not deprecated" visibility="public" > +<parameter name="resid" type="int"> +</parameter> +<parameter name="target" type="java.util.List<android.preference.PreferenceActivity.Header>"> +</parameter> </method> -<method name="onPreferenceTreeClick" +<method name="onBuildHeaders" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="target" type="java.util.List<android.preference.PreferenceActivity.Header>"> +</parameter> +</method> +<method name="onGetInitialFragment" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="onHeaderClick" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="header" type="android.preference.PreferenceActivity.Header"> +</parameter> +<parameter name="position" type="int"> +</parameter> +</method> +<method name="onIsHidingHeaders" return="boolean" abstract="false" native="false" @@ -134340,6 +134443,28 @@ deprecated="not deprecated" visibility="public" > +</method> +<method name="onIsMultiPane" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="onPreferenceTreeClick" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="deprecated" + visibility="public" +> <parameter name="preferenceScreen" type="android.preference.PreferenceScreen"> </parameter> <parameter name="preference" type="android.preference.Preference"> @@ -134352,12 +134477,55 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="preferenceScreen" type="android.preference.PreferenceScreen"> </parameter> </method> +<method name="startWithFragment" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragmentName" type="java.lang.String"> +</parameter> +</method> +<method name="switchToHeader" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragmentName" type="java.lang.String"> +</parameter> +</method> +</class> +<class name="PreferenceActivity.Header" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="PreferenceActivity.Header" + type="android.preference.PreferenceActivity.Header" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> </class> <class name="PreferenceCategory" extends="android.preference.PreferenceGroup" diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index daf6ce0..26cd9de 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -17,6 +17,7 @@ package android.app; import android.content.ComponentCallbacks; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; @@ -227,7 +228,25 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener public Fragment() { } - static Fragment instantiate(Activity activity, String fname) + /** + * Create a new instance of a Fragment with the given class name. This is + * the same as calling its empty constructor. + * + * @param context The calling context being used to instantiate the fragment. + * This is currently just used to get its ClassLoader. + * @param fname The class name of the fragment to instantiate. + * @return Returns a new fragment instance. + * @throws NoSuchMethodException The fragment does not have an empty constructor. + * @throws ClassNotFoundException The fragment class does not exist. + * @throws IllegalArgumentException Bad arguments supplied to fragment class + * constructor (should not happen). + * @throws InstantiationException Caller does not have permission to instantiate + * the fragment (for example its constructor is not public). + * @throws IllegalAccessException Caller does not have permission to access + * the given fragment class. + * @throws InvocationTargetException Failure running the fragment's constructor. + */ + public static Fragment instantiate(Context context, String fname) throws NoSuchMethodException, ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { @@ -235,7 +254,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener if (clazz == null) { // Class not found in the cache, see if it's real, and try to add it - clazz = activity.getClassLoader().loadClass(fname); + clazz = context.getClassLoader().loadClass(fname); sClassMap.put(fname, clazz); } return (Fragment)clazz.newInstance(); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index fdd3573..78ec638 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -196,6 +196,17 @@ public class Build { * </ul> */ public static final int GINGERBREAD = CUR_DEVELOPMENT; + + /** + * Next next version of Android. + * + * <p>Applications targeting this or a later release will get these + * new changes in behavior:</p> + * <ul> + * <li> Alerts UI change? + * </ul> + */ + public static final int HONEYCOMB = CUR_DEVELOPMENT; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 4686978..fdc874b 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -16,71 +16,96 @@ package android.preference; -import android.app.Activity; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.app.Fragment; import android.app.ListActivity; +import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.View.OnClickListener; +import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; /** - * Shows a hierarchy of {@link Preference} objects as - * lists, possibly spanning multiple screens. These preferences will - * automatically save to {@link SharedPreferences} as the user interacts with - * them. To retrieve an instance of {@link SharedPreferences} that the - * preference hierarchy in this activity will use, call - * {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)} - * with a context in the same package as this activity. - * <p> - * Furthermore, the preferences shown will follow the visual style of system - * preferences. It is easy to create a hierarchy of preferences (that can be - * shown on multiple screens) via XML. For these reasons, it is recommended to - * use this activity (as a superclass) to deal with preferences in applications. - * <p> - * A {@link PreferenceScreen} object should be at the top of the preference - * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy - * denote a screen break--that is the preferences contained within subsequent - * {@link PreferenceScreen} should be shown on another screen. The preference - * framework handles showing these other screens from the preference hierarchy. - * <p> - * The preference hierarchy can be formed in multiple ways: - * <li> From an XML file specifying the hierarchy - * <li> From different {@link Activity Activities} that each specify its own - * preferences in an XML file via {@link Activity} meta-data - * <li> From an object hierarchy rooted with {@link PreferenceScreen} - * <p> - * To inflate from XML, use the {@link #addPreferencesFromResource(int)}. The - * root element should be a {@link PreferenceScreen}. Subsequent elements can point - * to actual {@link Preference} subclasses. As mentioned above, subsequent - * {@link PreferenceScreen} in the hierarchy will result in the screen break. - * <p> - * To specify an {@link Intent} to query {@link Activity Activities} that each - * have preferences, use {@link #addPreferencesFromIntent}. Each - * {@link Activity} can specify meta-data in the manifest (via the key - * {@link PreferenceManager#METADATA_KEY_PREFERENCES}) that points to an XML - * resource. These XML resources will be inflated into a single preference - * hierarchy and shown by this activity. - * <p> - * To specify an object hierarchy rooted with {@link PreferenceScreen}, use - * {@link #setPreferenceScreen(PreferenceScreen)}. - * <p> - * As a convenience, this activity implements a click listener for any - * preference in the current hierarchy, see - * {@link #onPreferenceTreeClick(PreferenceScreen, Preference)}. + * This is the base class for an activity to show a hierarchy of preferences + * to the user. Prior to {@link android.os.Build.VERSION_CODES#HONEYCOMB} + * this class only allowed the display of a single set of preference; this + * functionality should now be found in the new {@link PreferenceFragment} + * class. If you are using PreferenceActivity in its old mode, the documentation + * there applies to the deprecated APIs here. + * + * <p>This activity shows one or more headers of preferences, each of with + * is associated with a {@link PreferenceFragment} to display the preferences + * of that header. The actual layout and display of these associations can + * however vary; currently there are two major approaches it may take: + * + * <ul> + * <li>On a small screen it may display only the headers as a single list + * when first launched. Selecting one of the header items will re-launch + * the activity with it only showing the PreferenceFragment of that header. + * <li>On a large screen in may display both the headers and current + * PreferenceFragment together as panes. Selecting a header item switches + * to showing the correct PreferenceFragment for that item. + * </ul> + * + * <p>Subclasses of PreferenceActivity should implement + * {@link #onBuildHeaders} to populate the header list with the desired + * items. Doing this implicitly switches the class into its new "headers + * + fragments" mode rather than the old style of just showing a single + * preferences list. + * + * <a name="SampleCode"></a> + * <h3>Sample Code</h3> + * + * <p>The following sample code shows a simple preference activity that + * has two different sets of preferences. The implementation, consisting + * of the activity itself as well as its two preference fragments is:</p> + * + * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/PreferenceWithHeaders.java + * activity} * - * @see Preference - * @see PreferenceScreen + * <p>The preference_headers resource describes the headers to be displayed + * and the fragments associated with them. It is: + * + * {@sample development/samples/ApiDemos/res/xml/preference_headers.xml headers} + * + * See {@link PreferenceFragment} for information on implementing the + * fragments themselves. */ public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener { + private static final String TAG = "PreferenceActivity"; private static final String PREFERENCES_TAG = "android:preferences"; + private static final String EXTRA_PREFS_SHOW_FRAGMENT = ":android:show_fragment"; + + private static final String EXTRA_PREFS_NO_HEADERS = ":android:no_headers"; + // extras that allow any preference activity to be launched as part of a wizard // show Back and Next buttons? takes boolean parameter @@ -92,12 +117,26 @@ public abstract class PreferenceActivity extends ListActivity implements private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text"; private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text"; - private Button mNextButton; + // --- State for new mode when showing a list of headers + prefs fragment + + private final ArrayList<Header> mHeaders = new ArrayList<Header>(); + + private HeaderAdapter mAdapter; + + private View mPrefsContainer; + + private boolean mSinglePane; + + // --- State for old mode when showing a single preference list private PreferenceManager mPreferenceManager; private Bundle mSavedInstanceState; + // --- Common state + + private Button mNextButton; + /** * The starting request code given out to preference framework. */ @@ -116,12 +155,128 @@ public abstract class PreferenceActivity extends ListActivity implements } }; + private class HeaderViewHolder { + ImageView icon; + TextView title; + TextView summary; + } + + private class HeaderAdapter extends ArrayAdapter<Header> { + private LayoutInflater mInflater; + + public HeaderAdapter(Context context, List<Header> objects) { + super(context, 0, objects); + mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + HeaderViewHolder holder; + View view; + + if (convertView == null) { + view = mInflater.inflate(com.android.internal.R.layout.preference_list_item, + parent, false); + holder = new HeaderViewHolder(); + holder.icon = (ImageView)view.findViewById( + com.android.internal.R.id.icon); + holder.title = (TextView)view.findViewById( + com.android.internal.R.id.title); + holder.summary = (TextView)view.findViewById( + com.android.internal.R.id.summary); + view.setTag(holder); + } else { + view = convertView; + holder = (HeaderViewHolder)view.getTag(); + } + + Header header = getItem(position); + if (header.icon != null) holder.icon.setImageDrawable(header.icon); + else if (header.iconRes != 0) holder.icon.setImageResource(header.iconRes); + if (header.title != null) holder.title.setText(header.title); + if (header.summary != null) holder.summary.setText(header.summary); + + return view; + } + } + + /** + * Description of a single Header item that the user can select. + */ + public static class Header { + /** + * Title of the header that is shown to the user. + */ + CharSequence title; + + /** + * Optional summary describing what this header controls. + */ + CharSequence summary; + + /** + * Optional icon resource to show for this header. + */ + int iconRes; + + /** + * Optional icon drawable to show for this header. (If this is non-null, + * the iconRes will be ignored.) + */ + Drawable icon; + + /** + * Full class name of the fragment to display when this header is + * selected. + */ + String fragment; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(com.android.internal.R.layout.preference_list_content); + mPrefsContainer = findViewById(com.android.internal.R.id.prefs); + boolean hidingHeaders = onIsHidingHeaders(); + mSinglePane = hidingHeaders || !onIsMultiPane(); + String initialFragment = getIntent().getStringExtra(EXTRA_PREFS_SHOW_FRAGMENT); + + if (initialFragment != null && mSinglePane) { + // If we are just showing a fragment, we want to run in + // new fragment mode, but don't need to compute and show + // the headers. + getListView().setVisibility(View.GONE); + mPrefsContainer.setVisibility(View.VISIBLE); + switchToHeader(initialFragment); + + } else { + // We need to try to build the headers. + onBuildHeaders(mHeaders); + + // If there are headers, then at this point we need to show + // them and, depending on the screen, we may also show in-line + // the currently selected preference fragment. + if (mHeaders.size() > 0) { + mAdapter = new HeaderAdapter(this, mHeaders); + setListAdapter(mAdapter); + if (!mSinglePane) { + mPrefsContainer.setVisibility(View.VISIBLE); + switchToHeader(initialFragment != null + ? initialFragment : onGetInitialFragment()); + } + + // If there are no headers, we are in the old "just show a screen + // of preferences" mode. + } else { + mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE); + mPreferenceManager.setOnPreferenceTreeClickListener(this); + } + } + + getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); + // see if we should show Back/Next buttons Intent intent = getIntent(); if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) { @@ -163,45 +318,165 @@ public abstract class PreferenceActivity extends ListActivity implements } } } + } + + /** + * Called to determine if the activity should run in multi-pane mode. + * The default implementation returns true if the screen is large + * enough. + */ + public boolean onIsMultiPane() { + Configuration config = getResources().getConfiguration(); + if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) + == Configuration.SCREENLAYOUT_SIZE_XLARGE + && config.orientation == Configuration.ORIENTATION_LANDSCAPE) { + return true; + } + return false; + } + + /** + * Called to determine whether the header list should be hidden. The + * default implementation hides the list if the activity is being re-launched + * when not in multi-pane mode. + */ + public boolean onIsHidingHeaders() { + return getIntent().getBooleanExtra(EXTRA_PREFS_NO_HEADERS, false); + } + + /** + * Called to determine the initial fragment to be shown. The default + * implementation simply returns the fragment of the first header. + */ + public String onGetInitialFragment() { + return mHeaders.get(0).fragment; + } + + /** + * Called when the activity needs its list of headers build. By + * implementing this and adding at least one item to the list, you + * will cause the activity to run in its modern fragment mode. Note + * that this function may not always be called; for example, if the + * activity has been asked to display a particular fragment without + * the header list, there is no need to build the headers. + * + * <p>Typical implementations will use {@link #loadHeadersFromResource} + * to fill in the list from a resource. + * + * @param target The list in which to place the headers. + */ + public void onBuildHeaders(List<Header> target) { + } + + /** + * Parse the given XML file as a header description, adding each + * parsed Header into the target list. + * + * @param resid The XML resource to load and parse. + * @param target The list in which the parsed headers should be placed. + */ + public void loadHeadersFromResource(int resid, List<Header> target) { + XmlResourceParser parser = null; + try { + parser = getResources().getXml(resid); + AttributeSet attrs = Xml.asAttributeSet(parser); + + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + + String nodeName = parser.getName(); + if (!"PreferenceHeaders".equals(nodeName)) { + throw new RuntimeException( + "XML document must start with <PreferenceHeaders> tag; found" + + nodeName + " at " + parser.getPositionDescription()); + } + + int outerDepth = parser.getDepth(); + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + nodeName = parser.getName(); + if ("Header".equals(nodeName)) { + Header header = new Header(); + + TypedArray sa = getResources().obtainAttributes(attrs, + com.android.internal.R.styleable.PreferenceHeader); + header.title = sa.getText( + com.android.internal.R.styleable.PreferenceHeader_title); + header.summary = sa.getText( + com.android.internal.R.styleable.PreferenceHeader_summary); + header.iconRes = sa.getResourceId( + com.android.internal.R.styleable.PreferenceHeader_icon, 0); + header.fragment = sa.getString( + com.android.internal.R.styleable.PreferenceHeader_fragment); + sa.recycle(); + + target.add(header); + + XmlUtils.skipCurrentTag(parser); + } else { + XmlUtils.skipCurrentTag(parser); + } + } + + } catch (XmlPullParserException e) { + throw new RuntimeException("Error parsing headers", e); + } catch (IOException e) { + throw new RuntimeException("Error parsing headers", e); + } finally { + if (parser != null) parser.close(); + } - mPreferenceManager = onCreatePreferenceManager(); - getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); } @Override protected void onStop() { super.onStop(); - mPreferenceManager.dispatchActivityStop(); + if (mPreferenceManager != null) { + mPreferenceManager.dispatchActivityStop(); + } } @Override protected void onDestroy() { super.onDestroy(); - mPreferenceManager.dispatchActivityDestroy(); + + if (mPreferenceManager != null) { + mPreferenceManager.dispatchActivityDestroy(); + } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - final PreferenceScreen preferenceScreen = getPreferenceScreen(); - if (preferenceScreen != null) { - Bundle container = new Bundle(); - preferenceScreen.saveHierarchyState(container); - outState.putBundle(PREFERENCES_TAG, container); + if (mPreferenceManager != null) { + final PreferenceScreen preferenceScreen = getPreferenceScreen(); + if (preferenceScreen != null) { + Bundle container = new Bundle(); + preferenceScreen.saveHierarchyState(container); + outState.putBundle(PREFERENCES_TAG, container); + } } } @Override protected void onRestoreInstanceState(Bundle state) { - Bundle container = state.getBundle(PREFERENCES_TAG); - if (container != null) { - final PreferenceScreen preferenceScreen = getPreferenceScreen(); - if (preferenceScreen != null) { - preferenceScreen.restoreHierarchyState(container); - mSavedInstanceState = state; - return; + if (mPreferenceManager != null) { + Bundle container = state.getBundle(PREFERENCES_TAG); + if (container != null) { + final PreferenceScreen preferenceScreen = getPreferenceScreen(); + if (preferenceScreen != null) { + preferenceScreen.restoreHierarchyState(container); + mSavedInstanceState = state; + return; + } } } @@ -214,13 +489,76 @@ public abstract class PreferenceActivity extends ListActivity implements protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data); + if (mPreferenceManager != null) { + mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data); + } } @Override public void onContentChanged() { super.onContentChanged(); - postBindPreferences(); + + if (mPreferenceManager != null) { + postBindPreferences(); + } + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + + if (mAdapter != null) { + onHeaderClick(mHeaders.get(position), position); + } + } + + /** + * Called when the user selects an item in the header list. The default + * implementation will call either {@link #startWithFragment(String)} + * or {@link #switchToHeader(String)} as appropriate. + * + * @param header The header that was selected. + * @param position The header's position in the list. + */ + public void onHeaderClick(Header header, int position) { + if (mSinglePane) { + startWithFragment(header.fragment); + } else { + switchToHeader(header.fragment); + } + } + + /** + * Start a new instance of this activity, showing only the given + * preference fragment. When launched in this mode, the header list + * will be hidden and the given preference fragment will be instantiated + * and fill the entire activity. + * + * @param fragmentName The name of the fragment to display. + */ + public void startWithFragment(String fragmentName) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(this, getClass()); + intent.putExtra(EXTRA_PREFS_SHOW_FRAGMENT, fragmentName); + intent.putExtra(EXTRA_PREFS_NO_HEADERS, true); + startActivity(intent); + } + + /** + * When in two-pane mode, switch the fragment pane to show the given + * preference fragment. + * + * @param fragmentName The name of the fragment to display. + */ + public void switchToHeader(String fragmentName) { + Fragment f; + try { + f = Fragment.instantiate(this, fragmentName); + } catch (Exception e) { + Log.w(TAG, "Failure instantiating fragment " + fragmentName, e); + return; + } + openFragmentTransaction().replace(com.android.internal.R.id.prefs, f).commit(); } /** @@ -246,27 +584,24 @@ public abstract class PreferenceActivity extends ListActivity implements } /** - * Creates the {@link PreferenceManager}. - * - * @return The {@link PreferenceManager} used by this activity. - */ - private PreferenceManager onCreatePreferenceManager() { - PreferenceManager preferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE); - preferenceManager.setOnPreferenceTreeClickListener(this); - return preferenceManager; - } - - /** * Returns the {@link PreferenceManager} used by this activity. * @return The {@link PreferenceManager}. + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public PreferenceManager getPreferenceManager() { return mPreferenceManager; } private void requirePreferenceManager() { if (mPreferenceManager == null) { - throw new RuntimeException("This should be called after super.onCreate."); + if (mAdapter == null) { + throw new RuntimeException("This should be called after super.onCreate."); + } + throw new RuntimeException( + "Modern two-pane PreferenceActivity requires use of a PreferenceFragment"); } } @@ -274,8 +609,14 @@ public abstract class PreferenceActivity extends ListActivity implements * Sets the root of the preference hierarchy that this activity is showing. * * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy. + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public void setPreferenceScreen(PreferenceScreen preferenceScreen) { + requirePreferenceManager(); + if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) { postBindPreferences(); CharSequence title = getPreferenceScreen().getTitle(); @@ -291,16 +632,27 @@ public abstract class PreferenceActivity extends ListActivity implements * * @return The {@link PreferenceScreen} that is the root of the preference * hierarchy. + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public PreferenceScreen getPreferenceScreen() { - return mPreferenceManager.getPreferenceScreen(); + if (mPreferenceManager != null) { + return mPreferenceManager.getPreferenceScreen(); + } + return null; } /** * Adds preferences from activities that match the given {@link Intent}. * * @param intent The {@link Intent} to query activities. + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public void addPreferencesFromIntent(Intent intent) { requirePreferenceManager(); @@ -312,7 +664,11 @@ public abstract class PreferenceActivity extends ListActivity implements * preference hierarchy. * * @param preferencesResId The XML resource ID to inflate. + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public void addPreferencesFromResource(int preferencesResId) { requirePreferenceManager(); @@ -322,7 +678,11 @@ public abstract class PreferenceActivity extends ListActivity implements /** * {@inheritDoc} + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { return false; } @@ -333,7 +693,11 @@ public abstract class PreferenceActivity extends ListActivity implements * @param key The key of the preference to retrieve. * @return The {@link Preference} with the key, or null. * @see PreferenceGroup#findPreference(CharSequence) + * + * @deprecated This function is not relevant for a modern fragment-based + * PreferenceActivity. */ + @Deprecated public Preference findPreference(CharSequence key) { if (mPreferenceManager == null) { diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java index f85bc9e..ac61574 100644 --- a/core/java/android/preference/PreferenceFragment.java +++ b/core/java/android/preference/PreferenceFragment.java @@ -37,6 +37,17 @@ import android.widget.ListView; * {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)} * with a context in the same package as this fragment. * <p> + * Furthermore, the preferences shown will follow the visual style of system + * preferences. It is easy to create a hierarchy of preferences (that can be + * shown on multiple screens) via XML. For these reasons, it is recommended to + * use this fragment (as a superclass) to deal with preferences in applications. + * <p> + * A {@link PreferenceScreen} object should be at the top of the preference + * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy + * denote a screen break--that is the preferences contained within subsequent + * {@link PreferenceScreen} should be shown on another screen. The preference + * framework handles showing these other screens from the preference hierarchy. + * <p> * The preference hierarchy can be formed in multiple ways: * <li> From an XML file specifying the hierarchy * <li> From different {@link Activity Activities} that each specify its own @@ -61,24 +72,21 @@ import android.widget.ListView; * As a convenience, this fragment implements a click listener for any * preference in the current hierarchy, see * {@link #onPreferenceTreeClick(PreferenceScreen, Preference)}. - * <p> - * See {@link PreferenceActivity} for more details. * * <a name="SampleCode"></a> * <h3>Sample Code</h3> * - * <p>The following sample code shows the use if a PreferenceFragment to - * embed preferences in a larger activity and switch between them. The content - * layout of the activity is:</p> + * <p>The following sample code shows a simple preference fragment that is + * populated from a resource. The resource it loads is:</p> * - * {@sample development/samples/ApiDemos/res/layout/fragment_preferences.xml layout} + * {@sample development/samples/ApiDemos/res/xml/preferences.xml preferences} * - * <p>The code using this layout consists of an activity and three fragments. - * One of the fragments is a list of categories the user can select; the other - * two are the different preference options for the categories.</p> + * <p>The fragment implementation itself simply populates the preferences + * when created. Note that the preferences framework takes care of loading + * the current values out of the app preferences and writing them when changed:</p> * - * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentPreferences.java - * activity} + * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/FragmentPreferences.java + * fragment} * * @see Preference * @see PreferenceScreen diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 03ada94..b4ece24 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -30,17 +30,17 @@ import java.util.Comparator; import java.util.Collections; /** - * A ListAdapter that manages a ListView backed by an array of arbitrary + * A concrete BaseAdapter that is backed by an array of arbitrary * objects. By default this class expects that the provided resource id references * a single TextView. If you want to use a more complex layout, use the constructors that * also takes a field id. That field id should reference a TextView in the larger layout * resource. * - * However the TextView is referenced, it will be filled with the toString() of each object in + * <p>However the TextView is referenced, it will be filled with the toString() of each object in * the array. You can add lists or arrays of custom objects. Override the toString() method * of your objects to determine what text will be displayed for the item in the list. * - * To use something other than TextViews for the array display, for instance, ImageViews, + * <p>To use something other than TextViews for the array display, for instance, ImageViews, * or to have some of data besides toString() results fill the views, * override {@link #getView(int, View, ViewGroup)} to return the type of view you want. */ diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml index 844d338..d530e96 100644 --- a/core/res/res/layout/preference_list_content.xml +++ b/core/res/res/layout/preference_list_content.xml @@ -23,17 +23,29 @@ android:layout_height="match_parent" android:layout_width="match_parent"> - <ListView android:id="@android:id/list" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:layout_weight="1" - android:drawSelectorOnTop="false" - android:scrollbarAlwaysDrawVerticalTrack="true" - /> + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1"> + + <ListView android:id="@android:id/list" + android:layout_width="0px" + android:layout_height="match_parent" + android:layout_weight="1" + android:drawSelectorOnTop="false" + android:scrollbarAlwaysDrawVerticalTrack="true" /> + + <FrameLayout android:id="@+id/prefs" + android:layout_width="0px" + android:layout_height="match_parent" + android:layout_weight="3" + android:visibility="gone" /> + </LinearLayout> <RelativeLayout android:id="@+id/button_bar" android:layout_height="wrap_content" - android:layout_width="fill_parent" + android:layout_width="match_parent" android:layout_weight="0" android:background="@android:drawable/bottom_bar" android:visibility="gone"> diff --git a/core/res/res/layout/preference_list_item.xml b/core/res/res/layout/preference_list_item.xml new file mode 100644 index 0000000..3b888b4 --- /dev/null +++ b/core/res/res/layout/preference_list_item.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2006 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. +--> + +<!-- Layout for a preference category item, containing an icon and label. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+android:id/widget_frame" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:gravity="center_vertical" + android:paddingRight="?android:attr/scrollbarSize"> + + <ImageView + android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="6dip" + android:layout_marginRight="6dip" + android:layout_gravity="center" /> + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="2dip" + android:layout_marginRight="6dip" + android:layout_marginTop="6dip" + android:layout_marginBottom="6dip" + android:layout_weight="1"> + + <TextView android:id="@+android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceLarge" + android:ellipsize="marquee" + android:fadingEdge="horizontal" /> + + <TextView android:id="@+android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_alignLeft="@android:id/title" + android:textAppearance="?android:attr/textAppearanceSmall" + android:maxLines="2" /> + + </RelativeLayout> + +</LinearLayout> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 974733f..728f999 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3428,6 +3428,19 @@ <attr name="orderingFromXml" format="boolean" /> </declare-styleable> + <!-- Attribute for a header describing the item shown in the top-level list + from which the selects the set of preference to dig in to. --> + <declare-styleable name="PreferenceHeader"> + <!-- The title of the item that is shown to the user. --> + <attr name="title" /> + <!-- The summary for the item. --> + <attr name="summary" format="string" /> + <!-- An icon for the item. --> + <attr name="icon" /> + <!-- The fragment that is displayed when the user selects this item. --> + <attr name="fragment" format="string" /> + </declare-styleable> + <!-- WARNING: If adding attributes to Preference, make sure it does not conflict with a View's attributes. Some subclasses (e.g., EditTextPreference) proxy all attributes to its EditText widget. --> @@ -3440,7 +3453,7 @@ <!-- The title for the Preference in a PreferenceActivity screen. --> <attr name="title" /> <!-- The summary for the Preference in a PreferenceActivity screen. --> - <attr name="summary" format="string" /> + <attr name="summary" /> <!-- The order for the Preference (lower values are to be ordered first). If this is not specified, the default orderin will be alphabetic. --> <attr name="order" format="integer" /> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d1021a5..fc207ca 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1314,6 +1314,7 @@ <public type="attr" name="valueType" /> <public type="attr" name="propertyName" /> <public type="attr" name="ordering" /> + <public type="attr" name="fragment" /> <public type="id" name="home" /> <!-- Context menu ID for the "Select text..." menu item to switch to text |
