Some new preferences features.

- You can add arbitrary stuff at the bottom of the header list.
- You can associated an intent with a header to have that launched
  when the header is clicked.
- You can change the current header when the header list is rebuilt
  after the first time.

Change-Id: I889512beff0c2902a790434e5cde9ce6df74d0c2
diff --git a/api/current.xml b/api/current.xml
index d261a97..b79e6d1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -139228,6 +139228,17 @@
  visibility="public"
 >
 </method>
+<method name="onGetNewHeader"
+ return="android.preference.PreferenceActivity.Header"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onHeaderClick"
  return="void"
  abstract="false"
@@ -139295,6 +139306,19 @@
 <parameter name="preference" type="android.preference.Preference">
 </parameter>
 </method>
+<method name="setListFooter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
 <method name="setPreferenceScreen"
  return="void"
  abstract="false"
@@ -139428,6 +139452,16 @@
  visibility="public"
 >
 </field>
+<field name="intent"
+ type="android.content.Intent"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="summary"
  type="java.lang.CharSequence"
  transient="false"
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 70a2b80..4889c19 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -42,6 +42,7 @@
 import android.view.View.OnClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -158,6 +159,8 @@
 
     private HeaderAdapter mAdapter;
 
+    private FrameLayout mListFooter;
+
     private View mPrefsContainer;
 
     private boolean mSinglePane;
@@ -189,6 +192,10 @@
                 case MSG_BUILD_HEADERS:
                     onBuildHeaders(mHeaders);
                     mAdapter.notifyDataSetChanged();
+                    Header header = onGetNewHeader();
+                    if (header != null && header.fragment != null) {
+                        switchToHeader(header.fragment, header.fragmentArguments);
+                    }
                     break;
             }
         }
@@ -287,6 +294,11 @@
          * instantiated.
          */
         public Bundle fragmentArguments;
+
+        /**
+         * Intent to launch when the preference is selected.
+         */
+        public Intent intent;
     }
 
     @Override
@@ -295,6 +307,7 @@
 
         setContentView(com.android.internal.R.layout.preference_list_content);
 
+        mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
         mPrefsContainer = findViewById(com.android.internal.R.id.prefs);
         boolean hidingHeaders = onIsHidingHeaders();
         mSinglePane = hidingHeaders || !onIsMultiPane();
@@ -446,6 +459,16 @@
     }
 
     /**
+     * Called after the header list has been updated ({@link #onBuildHeaders}
+     * has been called and returned due to {@link #invalidateHeaders()}) to
+     * specify the header that should now be selected.  The default implementation
+     * returns null to keep whatever header is currently selected.
+     */
+    public Header onGetNewHeader() {
+        return null;
+    }
+
+    /**
      * 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
@@ -498,7 +521,7 @@
 
             Bundle curBundle = null;
 
-            int outerDepth = parser.getDepth();
+            final 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) {
@@ -524,7 +547,27 @@
                     if (curBundle == null) {
                         curBundle = new Bundle();
                     }
-                    getResources().parseBundleExtras(parser, curBundle);
+
+                    final int innerDepth = parser.getDepth();
+                    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                           && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                            continue;
+                        }
+
+                        String innerNodeName = parser.getName();
+                        if (innerNodeName.equals("extra")) {
+                            getResources().parseBundleExtra("extra", attrs, curBundle);
+                            XmlUtils.skipCurrentTag(parser);
+
+                        } else if (innerNodeName.equals("intent")) {
+                            header.intent = Intent.parseIntent(getResources(), parser, attrs);
+
+                        } else {
+                            XmlUtils.skipCurrentTag(parser);
+                        }
+                    }
+
                     if (curBundle.size() > 0) {
                         header.fragmentArguments = curBundle;
                         curBundle = null;
@@ -546,6 +589,16 @@
 
     }
 
+    /**
+     * Set a footer that should be shown at the bottom of the header list.
+     */
+    public void setListFooter(View view) {
+        mListFooter.removeAllViews();
+        mListFooter.addView(view, new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.MATCH_PARENT,
+                FrameLayout.LayoutParams.WRAP_CONTENT));
+    }
+
     @Override
     protected void onStop() {
         super.onStop();
@@ -633,10 +686,14 @@
      * @param position The header's position in the list.
      */
     public void onHeaderClick(Header header, int position) {
-        if (mSinglePane) {
-            startWithFragment(header.fragment, header.fragmentArguments);
-        } else {
-            switchToHeader(header.fragment, header.fragmentArguments);
+        if (header.fragment != null) {
+            if (mSinglePane) {
+                startWithFragment(header.fragment, header.fragmentArguments);
+            } else {
+                switchToHeader(header.fragment, header.fragmentArguments);
+            }
+        } else if (header.intent != null) {
+            startActivity(header.intent);
         }
     }
 
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index eeba18e..fe950b2 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -29,12 +29,25 @@
         android:layout_height="0px"
         android:layout_weight="1">
 
-        <ListView android:id="@android:id/list"
+        <LinearLayout
+            android:orientation="vertical"
             android:layout_width="0px"
             android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:drawSelectorOnTop="false"
-            android:scrollbarAlwaysDrawVerticalTrack="true" />
+            android:layout_weight="1">
+
+            <ListView android:id="@android:id/list"
+                android:layout_width="match_parent"
+                android:layout_height="0px"
+                android:layout_weight="1"
+                android:drawSelectorOnTop="false"
+                android:scrollbarAlwaysDrawVerticalTrack="true" />
+
+            <FrameLayout android:id="@+id/list_footer"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0" />
+
+        </LinearLayout>
 
         <FrameLayout android:id="@+id/prefs"
                 android:layout_width="0px"