More fragment work:

- Introduce FragmentManager as a public API, deprecating the fragment
  APIs on Activity.  (They will be removed soon.)
- Add APIs to write a fragment reference to a bundle and later retrieve
  it.
- Add Fragment API to set another fragment as its target, for delivering
  results.
- Change when onInflate() is called and formalize its meaning in relation
  to the fragment arguments that were previously introduced.
- Change onDestroyView() to always be called, regardless of when
  onCreateView() returns.  It now also is called slightly differently,
  after the view hierarchy's state is saved.
- Fix some issues with DialogFragment's lifecycle with its associated
  Dialog and state save/restore.
- Preference can now have a Bundle associated with it to provide
  arguments to a fragment.  The data for this Bundle call be supplied
  via <extra> tags under a PreferenceScreen.
- PreferenceActivity's header XML tags are now <preference-headers>
  and <header>, and you can supply <extra> tags under a <header> to set
  arguments for the header's fragment.

Change-Id: I22c212c9fa862d50840201ca16e51f9de5ef0031
diff --git a/api/current.xml b/api/current.xml
index d35037e..4356852 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -21796,7 +21796,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="id" type="int">
@@ -21809,7 +21809,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="tag" type="java.lang.String">
@@ -23006,7 +23006,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -23043,7 +23043,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -23054,7 +23054,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="name" type="java.lang.String">
@@ -23069,7 +23069,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="id" type="int">
@@ -27856,6 +27856,28 @@
  visibility="public"
 >
 </method>
+<method name="getTargetFragment"
+ return="android.app.Fragment"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTargetRequestCode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getView"
  return="android.view.View"
  abstract="false"
@@ -28158,8 +28180,6 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="activity" type="android.app.Activity">
-</parameter>
 <parameter name="attrs" type="android.util.AttributeSet">
 </parameter>
 <parameter name="savedInstanceState" type="android.os.Bundle">
@@ -28291,7 +28311,7 @@
  native="false"
  synchronized="false"
  static="false"
- final="true"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -28324,6 +28344,21 @@
 <parameter name="retain" type="boolean">
 </parameter>
 </method>
+<method name="setTargetFragment"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+</method>
 <method name="startActivity"
  return="void"
  abstract="false"
@@ -137652,6 +137687,17 @@
  visibility="public"
 >
 </method>
+<method name="getExtras"
+ return="android.os.Bundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFragment"
  return="java.lang.String"
  abstract="false"
@@ -138095,6 +138141,17 @@
 <parameter name="defaultValue" type="java.lang.Object">
 </parameter>
 </method>
+<method name="peekExtras"
+ return="android.os.Bundle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="persistBoolean"
  return="boolean"
  abstract="false"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ec3cbc3..d40d7d8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1590,7 +1590,9 @@
     /**
      * Start a series of edit operations on the Fragments associated with
      * this activity.
+     * @deprecated use {@link #getFragmentManager}.
      */
+    @Deprecated
     public FragmentTransaction openFragmentTransaction() {
         return mFragments.openTransaction();
     }
@@ -1782,7 +1784,9 @@
      * from XML or as the container ID when added in a transaction.  This only
      * returns fragments that are currently added to the activity's content.
      * @return The fragment if found or null otherwise.
+     * @deprecated use {@link #getFragmentManager}.
      */
+    @Deprecated
     public Fragment findFragmentById(int id) {
         return mFragments.findFragmentById(id);
     }
@@ -1792,7 +1796,9 @@
      * from XML or as supplied when added in a transaction.  This only
      * returns fragments that are currently added to the activity's content.
      * @return The fragment if found or null otherwise.
+     * @deprecated use {@link #getFragmentManager}.
      */
+    @Deprecated
     public Fragment findFragmentByTag(String tag) {
         return mFragments.findFragmentByTag(tag);
     }
@@ -2078,7 +2084,9 @@
     /**
      * Pop the top state off the back stack.  Returns true if there was one
      * to pop, else false.
+     * @deprecated use {@link #getFragmentManager}.
      */
+    @Deprecated
     public boolean popBackStack() {
         return mFragments.popBackStack();
     }
@@ -2091,7 +2099,9 @@
      * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
      * the named state itself is popped. If null, only the top state is popped.
      * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
+     * @deprecated use {@link #getFragmentManager}.
      */
+    @Deprecated
     public boolean popBackStack(String name, int flags) {
         return mFragments.popBackStack(name, flags);
     }
@@ -2105,7 +2115,9 @@
      * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
      * the named state itself is popped.
      * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
+     * @deprecated use {@link #getFragmentManager}.
      */
+    @Deprecated
     public boolean popBackStack(int id, int flags) {
         return mFragments.popBackStack(id, flags);
     }
@@ -2116,7 +2128,7 @@
      * but you can override this to do whatever you want.
      */
     public void onBackPressed() {
-        if (!popBackStack()) {
+        if (!mFragments.popBackStack()) {
             finish();
         }
     }
@@ -3995,9 +4007,12 @@
             return null;
         }
         
+        String fname = attrs.getAttributeValue(null, "class");
         TypedArray a = 
             context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
-        String fname = a.getString(com.android.internal.R.styleable.Fragment_name);
+        if (fname == null) {
+            fname = a.getString(com.android.internal.R.styleable.Fragment_name);
+        }
         int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, 0);
         String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);
         a.recycle();
@@ -4020,14 +4035,14 @@
             fragment.mFragmentId = id;
             fragment.mTag = tag;
             fragment.mImmediateActivity = this;
+            // If this fragment is newly instantiated (either right now, or
+            // from last saved state), then give it the attributes to
+            // initialize itself.
+            if (!fragment.mRetaining) {
+                fragment.onInflate(attrs, fragment.mSavedFragmentState);
+            }
             mFragments.addFragment(fragment, true);
         }
-        // If this fragment is newly instantiated (either right now, or
-        // from last saved state), then give it the attributes to
-        // initialize itself.
-        if (!fragment.mRetaining) {
-            fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
-        }
         if (fragment.mView == null) {
             throw new IllegalStateException("Fragment " + fname
                     + " did not create a view.");
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 3124f0d..50e7421 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -79,6 +79,7 @@
 
     Dialog mDialog;
     boolean mDestroyed;
+    boolean mRemoved;
 
     public DialogFragment() {
     }
@@ -136,6 +137,7 @@
      */
     public int show(Activity activity, FragmentTransaction transaction, String tag) {
         transaction.add(this, tag);
+        mRemoved = false;
         mBackStackId = transaction.commit();
         return mBackStackId;
     }
@@ -149,12 +151,15 @@
     public void dismiss() {
         if (mDialog != null) {
             mDialog.dismiss();
+            mDialog = null;
         }
+        mRemoved = true;
         if (mBackStackId >= 0) {
-            getActivity().popBackStack(mBackStackId, Activity.POP_BACK_STACK_INCLUSIVE);
+            getFragmentManager().popBackStack(mBackStackId,
+                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
             mBackStackId = -1;
         } else {
-            FragmentTransaction ft = getActivity().openFragmentTransaction();
+            FragmentTransaction ft = getFragmentManager().openTransaction();
             ft.remove(this);
             ft.commit();
         }
@@ -193,15 +198,12 @@
     }
 
     public void onCancel(DialogInterface dialog) {
-        if (mBackStackId >= 0) {
-            // If this fragment is part of the back stack, then cancelling
-            // the dialog means popping off the back stack.
-            getActivity().popBackStack(mBackStackId, Activity.POP_BACK_STACK_INCLUSIVE);
-            mBackStackId = -1;
-        }
     }
 
     public void onDismiss(DialogInterface dialog) {
+        if (!mRemoved) {
+            dismiss();
+        }
     }
 
     @Override
@@ -241,7 +243,10 @@
     @Override
     public void onStart() {
         super.onStart();
-        mDialog.show();
+        if (mDialog != null) {
+            mRemoved = false;
+            mDialog.show();
+        }
     }
 
     @Override
@@ -262,17 +267,25 @@
     @Override
     public void onStop() {
         super.onStop();
-        mDialog.hide();
+        if (mDialog != null) {
+            mDialog.hide();
+        }
     }
 
     /**
-     * Detach from list view.
+     * Remove dialog.
      */
     @Override
     public void onDestroyView() {
         super.onDestroyView();
         mDestroyed = true;
-        mDialog.dismiss();
-        mDialog = null;
+        if (mDialog != null) {
+            // Set removed here because this dismissal is just to hide
+            // the dialog -- we don't want this to cause the fragment to
+            // actually be removed.
+            mRemoved = true;
+            mDialog.dismiss();
+            mDialog = null;
+        }
     }
 }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index bc839d7..9a1db96 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -42,8 +42,6 @@
 import java.util.HashMap;
 
 final class FragmentState implements Parcelable {
-    static final String VIEW_STATE_TAG = "android:view_state";
-    
     final String mClassName;
     final int mIndex;
     final boolean mFromLayout;
@@ -90,8 +88,6 @@
         if (mSavedFragmentState != null) {
             mSavedFragmentState.setClassLoader(activity.getClassLoader());
             mInstance.mSavedFragmentState = mSavedFragmentState;
-            mInstance.mSavedViewState
-                    = mSavedFragmentState.getSparseParcelableArray(VIEW_STATE_TAG);
         }
         mInstance.setIndex(mIndex);
         mInstance.mFromLayout = mFromLayout;
@@ -160,6 +156,12 @@
     // Construction arguments;
     Bundle mArguments;
 
+    // Target fragment.
+    Fragment mTarget;
+
+    // Target request code.
+    int mTargetRequestCode;
+
     // True if the fragment is in the list of added fragments.
     boolean mAdded;
     
@@ -375,7 +377,7 @@
      * arguments supplied here will be retained across fragment destroy and
      * creation.
      */
-    final public void setArguments(Bundle args) {
+    public void setArguments(Bundle args) {
         if (mIndex >= 0) {
             throw new IllegalStateException("Fragment already active");
         }
@@ -391,6 +393,36 @@
     }
 
     /**
+     * Optional target for this fragment.  This may be used, for example,
+     * if this fragment is being started by another, and when done wants to
+     * give a result back to the first.  The target set here is retained
+     * across instances via {@link FragmentManager#putFragment
+     * FragmentManager.putFragment()}.
+     *
+     * @param fragment The fragment that is the target of this one.
+     * @param requestCode Optional request code, for convenience if you
+     * are going to call back with {@link #onActivityResult(int, int, Intent)}.
+     */
+    public void setTargetFragment(Fragment fragment, int requestCode) {
+        mTarget = fragment;
+        mTargetRequestCode = requestCode;
+    }
+
+    /**
+     * Return the target fragment set by {@link #setTargetFragment(Fragment)}.
+     */
+    final public Fragment getTargetFragment() {
+        return mTarget;
+    }
+
+    /**
+     * Return the target request code set by {@link #setTargetFragment(Fragment)}.
+     */
+    final public int getTargetRequestCode() {
+        return mTargetRequestCode;
+    }
+
+    /**
      * Return the Activity this fragment is currently associated with.
      */
     final public Activity getActivity() {
@@ -537,21 +569,30 @@
     /**
      * Called when a fragment is being created as part of a view layout
      * inflation, typically from setting the content view of an activity.  This
-     * will be called both the first time the fragment is created, as well
-     * later when it is being re-created from its saved state (which is also
-     * given here).
+     * will be called immediately after the fragment is created from a <fragment>
+     * tag in a layout file.  Note this is <em>before</em> the fragment's
+     * {@link #onAttach(Activity)} has been called; all you should do here is
+     * parse the attributes and save them away.  A convenient thing to do is
+     * simply copy them into a Bundle that is given to {@link #setArguments(Bundle)}.
      * 
-     * XXX This is kind-of yucky...  maybe we could just supply the
-     * AttributeSet to onCreate()?
+     * <p>This is called every time the fragment is inflated, even if it is
+     * being inflated into a new instance with saved state.  Because a fragment's
+     * arguments are retained across instances, it may make no sense to re-parse
+     * the attributes into new arguments.  You may want to first check
+     * {@link #getArguments()} and only parse the attributes if it returns null,
+     * the assumption being that if it is non-null those are the same arguments
+     * from the first time the fragment was inflated.  (That said, you may want
+     * to have layouts change for different configurations such as landscape
+     * and portrait, which can have different attributes.  If so, you will need
+     * to re-parse the attributes each time this is called to generate new
+     * arguments.)</p>
      * 
-     * @param activity The Activity that is inflating the fragment.
      * @param attrs The attributes at the tag where the fragment is
      * being created.
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onInflate(Activity activity, AttributeSet attrs,
-            Bundle savedInstanceState) {
+    public void onInflate(AttributeSet attrs, Bundle savedInstanceState) {
         mCalled = true;
     }
     
@@ -693,8 +734,10 @@
      * Called when the view previously created by {@link #onCreateView} has
      * been detached from the fragment.  The next time the fragment needs
      * to be displayed, a new view will be created.  This is called
-     * after {@link #onStop()} and before {@link #onDestroy()}; it is only
-     * called if {@link #onCreateView} returns a non-null View.
+     * after {@link #onStop()} and before {@link #onDestroy()}.  It is called
+     * <em>regardless</em> of whether {@link #onCreateView} returned a
+     * non-null view.  Internally it is called after the view's state has
+     * been saved but before it has been removed from its parent.
      */
     public void onDestroyView() {
         mCalled = true;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0556f05..f190d0d 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -166,13 +166,16 @@
 }
 
 /**
- * @hide
  * Container for fragments associated with an activity.
  */
-class FragmentManagerImpl implements FragmentManager {
+final class FragmentManagerImpl implements FragmentManager {
     static final boolean DEBUG = true;
     static final String TAG = "FragmentManager";
     
+    static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
+    static final String TARGET_STATE_TAG = "android:target_state";
+    static final String VIEW_STATE_TAG = "android:view_state";
+
     ArrayList<Runnable> mPendingActions;
     Runnable[] mTmpActions;
     boolean mExecutingActions;
@@ -201,7 +204,6 @@
             execPendingActions();
         }
     };
-    
     public FragmentTransaction openTransaction() {
         return new BackStackEntry(this);
     }
@@ -230,7 +232,10 @@
     }
 
     public Fragment getFragment(Bundle bundle, String key) {
-        int index = bundle.getInt(key);
+        int index = bundle.getInt(key, -1);
+        if (index == -1) {
+            return null;
+        }
         if (index >= mActive.size()) {
             throw new IllegalStateException("Fragement no longer exists for key "
                     + key + ": index " + index);
@@ -296,6 +301,16 @@
             switch (f.mState) {
                 case Fragment.INITIALIZING:
                     if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
+                    if (f.mSavedFragmentState != null) {
+                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
+                                FragmentManagerImpl.VIEW_STATE_TAG);
+                        f.mTarget = getFragment(f.mSavedFragmentState,
+                                FragmentManagerImpl.TARGET_STATE_TAG);
+                        if (f.mTarget != null) {
+                            f.mTargetRequestCode = f.mSavedFragmentState.getInt(
+                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
+                        }
+                    }
                     f.mActivity = mActivity;
                     f.mCalled = false;
                     f.onAttach(mActivity);
@@ -419,32 +434,32 @@
                     if (newState < Fragment.ACTIVITY_CREATED) {
                         if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
                         if (f.mView != null) {
-                            f.mCalled = false;
-                            f.onDestroyView();
-                            if (!f.mCalled) {
-                                throw new SuperNotCalledException("Fragment " + f
-                                        + " did not call through to super.onDestroyedView()");
-                            }
                             // Need to save the current view state if not
                             // done already.
                             if (!mActivity.isFinishing() && f.mSavedFragmentState == null) {
                                 saveFragmentViewState(f);
                             }
-                            if (f.mContainer != null) {
-                                if (mCurState > Fragment.INITIALIZING) {
-                                    Animatable anim = loadAnimatable(f, transit, true,
-                                            transitionStyle);
-                                    if (anim != null) {
-                                        if (anim instanceof Sequencer) {
-                                            ((Sequencer)anim).setTarget(f.mView);
-                                        } else if (anim instanceof PropertyAnimator) {
-                                            ((PropertyAnimator)anim).setTarget(f.mView);
-                                        }
-                                        anim.start();
+                        }
+                        f.mCalled = false;
+                        f.onDestroyView();
+                        if (!f.mCalled) {
+                            throw new SuperNotCalledException("Fragment " + f
+                                    + " did not call through to super.onDestroyedView()");
+                        }
+                        if (f.mView != null && f.mContainer != null) {
+                            if (mCurState > Fragment.INITIALIZING) {
+                                Animatable anim = loadAnimatable(f, transit, true,
+                                        transitionStyle);
+                                if (anim != null) {
+                                    if (anim instanceof Sequencer) {
+                                        ((Sequencer)anim).setTarget(f.mView);
+                                    } else if (anim instanceof PropertyAnimator) {
+                                        ((PropertyAnimator)anim).setTarget(f.mView);
                                     }
+                                    anim.start();
                                 }
-                                f.mContainer.removeView(f.mView);
                             }
+                            f.mContainer.removeView(f.mView);
                         }
                         f.mContainer = null;
                         f.mView = null;
@@ -908,7 +923,20 @@
                             fs.mSavedFragmentState = new Bundle();
                         }
                         fs.mSavedFragmentState.putSparseParcelableArray(
-                                FragmentState.VIEW_STATE_TAG, f.mSavedViewState);
+                                FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
+                    }
+                }
+
+                if (f.mTarget != null) {
+                    if (fs.mSavedFragmentState == null) {
+                        fs.mSavedFragmentState = new Bundle();
+                    }
+                    putFragment(fs.mSavedFragmentState,
+                            FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
+                    if (f.mTargetRequestCode != 0) {
+                        fs.mSavedFragmentState.putInt(
+                                FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
+                                f.mTargetRequestCode);
                     }
                 }
                 
@@ -976,7 +1004,7 @@
                 f.mAdded = false;
                 if (fs.mSavedFragmentState != null) {
                     f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
-                            FragmentState.VIEW_STATE_TAG);
+                            FragmentManagerImpl.VIEW_STATE_TAG);
                 }
             }
         }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 812af5a..9b23c1e 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1559,7 +1559,7 @@
     /**
      * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
      * an XML file.  You call this when you are at the parent tag of the
-     * extra tags, and it return once all of the child tags have been parsed.
+     * extra tags, and it will return once all of the child tags have been parsed.
      * This will call {@link #parseBundleExtra} for each extra tag encountered.
      * 
      * @param parser The parser from which to retrieve the extras.
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 117e507..ffc2862 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -90,6 +90,7 @@
     private String mKey;
     private Intent mIntent;
     private String mFragment;
+    private Bundle mExtras;
     private boolean mEnabled = true;
     private boolean mSelectable = true;
     private boolean mRequiresKey;
@@ -339,6 +340,26 @@
     }
 
     /**
+     * Return the extras Bundle object associated with this preference, creating
+     * a new Bundle if there currently isn't one.  You can use this to get and
+     * set individual extra key/value pairs.
+     */
+    public Bundle getExtras() {
+        if (mExtras == null) {
+            mExtras = new Bundle();
+        }
+        return mExtras;
+    }
+
+    /**
+     * Return the extras Bundle object associated with this preference,
+     * returning null if there is not currently one.
+     */
+    public Bundle peekExtras() {
+        return mExtras;
+    }
+
+    /**
      * Sets the layout resource that is inflated as the {@link View} to be shown
      * for this Preference. In most cases, the default layout is sufficient for
      * custom Preference objects and only the widget layout needs to be changed.
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 32bf170..6b00690 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -313,7 +313,7 @@
                 setListAdapter(mAdapter);
                 if (!mSinglePane) {
                     mPrefsContainer.setVisibility(View.VISIBLE);
-                    if (initialFragment != null) {
+                    if (initialFragment == null) {
                         Header h = onGetInitialHeader();
                         initialFragment = h.fragment;
                         initialArguments = h.fragmentArguments;
@@ -464,12 +464,14 @@
             }
 
             String nodeName = parser.getName();
-            if (!"PreferenceHeaders".equals(nodeName)) {
+            if (!"preference-headers".equals(nodeName)) {
                 throw new RuntimeException(
-                        "XML document must start with <PreferenceHeaders> tag; found"
+                        "XML document must start with <preference-headers> tag; found"
                         + nodeName + " at " + parser.getPositionDescription());
             }
 
+            Bundle curBundle = null;
+
             int outerDepth = parser.getDepth();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -478,7 +480,7 @@
                 }
 
                 nodeName = parser.getName();
-                if ("Header".equals(nodeName)) {
+                if ("header".equals(nodeName)) {
                     Header header = new Header();
 
                     TypedArray sa = getResources().obtainAttributes(attrs,
@@ -493,9 +495,16 @@
                             com.android.internal.R.styleable.PreferenceHeader_fragment);
                     sa.recycle();
 
-                    target.add(header);
+                    if (curBundle == null) {
+                        curBundle = new Bundle();
+                    }
+                    getResources().parseBundleExtras(parser, curBundle);
+                    if (curBundle.size() > 0) {
+                        header.fragmentArguments = curBundle;
+                        curBundle = null;
+                    }
 
-                    XmlUtils.skipCurrentTag(parser);
+                    target.add(header);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                 }
@@ -631,16 +640,17 @@
      * @param args Optional arguments to supply to the fragment.
      */
     public void switchToHeader(String fragmentName, Bundle args) {
-        popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
+        getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
 
         Fragment f = Fragment.instantiate(this, fragmentName, args);
-        openFragmentTransaction().replace(com.android.internal.R.id.prefs, f).commit();
+        getFragmentManager().openTransaction().replace(
+                com.android.internal.R.id.prefs, f).commit();
     }
 
     @Override
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
-        Fragment f = Fragment.instantiate(this, pref.getFragment());
-        openFragmentTransaction().replace(com.android.internal.R.id.prefs, f)
+        Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
+        getFragmentManager().openTransaction().replace(com.android.internal.R.id.prefs, f)
                 .addToBackStack(BACK_STACK_PREFS).commit();
         return true;
     }
diff --git a/core/java/android/preference/PreferenceInflater.java b/core/java/android/preference/PreferenceInflater.java
index 779e746..c21aa18 100644
--- a/core/java/android/preference/PreferenceInflater.java
+++ b/core/java/android/preference/PreferenceInflater.java
@@ -16,6 +16,8 @@
 
 package android.preference;
 
+import com.android.internal.util.XmlUtils;
+
 import java.io.IOException;
 import java.util.Map;
 
@@ -39,6 +41,7 @@
 class PreferenceInflater extends GenericInflater<Preference, PreferenceGroup> {
     private static final String TAG = "PreferenceInflater";
     private static final String INTENT_TAG_NAME = "intent";
+    private static final String EXTRA_TAG_NAME = "extra";
 
     private PreferenceManager mPreferenceManager;
     
@@ -73,8 +76,10 @@
             try {
                 intent = Intent.parseIntent(getContext().getResources(), parser, attrs);
             } catch (IOException e) {
-                Log.w(TAG, "Could not parse Intent.");
-                Log.w(TAG, e);
+                XmlPullParserException ex = new XmlPullParserException(
+                        "Error parsing preference");
+                ex.initCause(e);
+                throw ex;
             }
             
             if (intent != null) {
@@ -82,6 +87,18 @@
             }
             
             return true;
+        } else if (tag.equals(EXTRA_TAG_NAME)) {
+            getContext().getResources().parseBundleExtra(EXTRA_TAG_NAME, attrs,
+                    parentPreference.getExtras());
+            try {
+                XmlUtils.skipCurrentTag(parser);
+            } catch (IOException e) {
+                XmlPullParserException ex = new XmlPullParserException(
+                        "Error parsing preference");
+                ex.initCause(e);
+                throw ex;
+            }
+            return true;
         }
         
         return false;