Merge "Add a way to insert a parent bread crumb so that deep linked settings can navigate up."
diff --git a/api/current.xml b/api/current.xml
index e2ceb3f..008de2b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -29871,6 +29871,36 @@
 <parameter name="a" type="android.app.Activity">
 </parameter>
 </method>
+<method name="setMaxVisible"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="visibleCrumbs" type="int">
+</parameter>
+</method>
+<method name="setParentTitle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.CharSequence">
+</parameter>
+<parameter name="shortTitle" type="java.lang.CharSequence">
+</parameter>
+<parameter name="listener" type="android.view.View.OnClickListener">
+</parameter>
+</method>
 <method name="setTitle"
  return="void"
  abstract="false"
@@ -148256,6 +148286,23 @@
 <parameter name="view" type="android.view.View">
 </parameter>
 </method>
+<method name="setParentTitle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.CharSequence">
+</parameter>
+<parameter name="shortTitle" type="java.lang.CharSequence">
+</parameter>
+<parameter name="listener" type="android.view.View.OnClickListener">
+</parameter>
+</method>
 <method name="setPreferenceScreen"
  return="void"
  abstract="false"
@@ -251222,7 +251269,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index 8d76ffe..fb89099 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -45,6 +45,10 @@
 
     // Hahah
     BackStackRecord mTopEntry;
+    BackStackRecord mParentEntry;
+
+    /** Listener to inform when a parent entry is clicked */
+    private OnClickListener mParentClickListener;
 
     public FragmentBreadCrumbs(Context context) {
         this(context, null);
@@ -75,27 +79,51 @@
     }
 
     /**
-     * The maximum number of crumbs to show.
-     * @hide
+     * The maximum number of breadcrumbs to show. Older fragment headers will be hidden from view.
+     * @param visibleCrumbs the number of visible breadcrumbs. This should be greater than zero.
      */
     public void setMaxVisible(int visibleCrumbs) {
+        if (visibleCrumbs < 1) {
+            throw new IllegalArgumentException("visibleCrumbs must be greater than zero");
+        }
         mMaxVisible = visibleCrumbs;
     }
 
     /**
+     * Inserts an optional parent entry at the first position in the breadcrumbs. Selecting this
+     * entry will result in a call to the specified listener's 
+     * {@link android.view.View.OnClickListener#onClick(View)}
+     * method.
+     *
+     * @param title the title for the parent entry
+     * @param shortTitle the short title for the parent entry
+     * @param listener the {@link android.view.View.OnClickListener} to be called when clicked.
+     * A null will result in no action being taken when the parent entry is clicked.
+     */
+    public void setParentTitle(CharSequence title, CharSequence shortTitle,
+            OnClickListener listener) {
+        mParentEntry = createBackStackEntry(title, shortTitle);
+        mParentClickListener = listener;
+        updateCrumbs();
+    }
+
+    private BackStackRecord createBackStackEntry(CharSequence title, CharSequence shortTitle) {
+        if (title == null) return null;
+
+        final BackStackRecord entry = new BackStackRecord(
+                (FragmentManagerImpl) mActivity.getFragmentManager());
+        entry.setBreadCrumbTitle(title);
+        entry.setBreadCrumbShortTitle(shortTitle);
+        return entry;
+    }
+
+    /**
      * Set a custom title for the bread crumbs.  This will be the first entry
      * shown at the left, representing the root of the bread crumbs.  If the
      * title is null, it will not be shown.
      */
     public void setTitle(CharSequence title, CharSequence shortTitle) {
-        if (title == null) {
-            mTopEntry = null;
-        } else {
-            mTopEntry = new BackStackRecord((FragmentManagerImpl)
-                    mActivity.getFragmentManager());
-            mTopEntry.setBreadCrumbTitle(title);
-            mTopEntry.setBreadCrumbShortTitle(shortTitle);
-        }
+        mTopEntry = createBackStackEntry(title, shortTitle);
         updateCrumbs();
     }
 
@@ -151,41 +179,66 @@
         updateCrumbs();
     }
 
+    /**
+     * Returns the number of entries before the backstack, including the title of the current
+     * fragment and any custom parent title that was set.
+     */
+    private int getPreEntryCount() {
+        return (mTopEntry != null ? 1 : 0) + (mParentEntry != null ? 1 : 0);
+    }
+
+    /**
+     * Returns the pre-entry corresponding to the index. If there is a parent and a top entry
+     * set, parent has an index of zero and top entry has an index of 1. Returns null if the
+     * specified index doesn't exist or is null.
+     * @param index should not be more than {@link #getPreEntryCount()} - 1
+     */
+    private BackStackEntry getPreEntry(int index) {
+        // If there's a parent entry, then return that for zero'th item, else top entry.
+        if (mParentEntry != null) {
+            return index == 0 ? mParentEntry : mTopEntry;
+        } else {
+            return mTopEntry;
+        }
+    }
+
     void updateCrumbs() {
         FragmentManager fm = mActivity.getFragmentManager();
         int numEntries = fm.countBackStackEntries();
+        int numPreEntries = getPreEntryCount();
         int numViews = mContainer.getChildCount();
-        for (int i = mTopEntry != null ? -1 : 0; i < numEntries; i++) {
-            BackStackEntry bse = i == -1 ? mTopEntry : fm.getBackStackEntry(i);
-            int viewI = mTopEntry != null ? i + 1 : i;
-            if (viewI < numViews) {
-                View v = mContainer.getChildAt(viewI);
+        for (int i = 0; i < numEntries + numPreEntries; i++) {
+            BackStackEntry bse = i < numPreEntries
+                    ? getPreEntry(i)
+                    : fm.getBackStackEntry(i - numPreEntries);
+            if (i < numViews) {
+                View v = mContainer.getChildAt(i);
                 Object tag = v.getTag();
                 if (tag != bse) {
-                    for (int j = viewI; j < numViews; j++) {
-                        mContainer.removeViewAt(viewI);
+                    for (int j = i; j < numViews; j++) {
+                        mContainer.removeViewAt(i);
                     }
-                    numViews = viewI;
+                    numViews = i;
                 }
             }
-            if (viewI >= numViews) {
+            if (i >= numViews) {
                 final View item = mInflater.inflate(
                         com.android.internal.R.layout.fragment_bread_crumb_item,
                         this, false);
                 final TextView text = (TextView) item.findViewById(com.android.internal.R.id.title);
                 text.setText(bse.getBreadCrumbTitle());
                 text.setTag(bse);
-                if (viewI == 0) {
+                if (i == 0) {
                     item.findViewById(com.android.internal.R.id.left_icon).setVisibility(View.GONE);
                 }
                 mContainer.addView(item);
                 text.setOnClickListener(mOnClickListener);
             }
         }
-        int viewI = mTopEntry != null ? numEntries + 1 : numEntries;
+        int viewI = numEntries + numPreEntries;
         numViews = mContainer.getChildCount();
         while (numViews > viewI) {
-            mContainer.removeViewAt(numViews-1);
+            mContainer.removeViewAt(numViews - 1);
             numViews--;
         }
         // Adjust the visibility and availability of the bread crumbs and divider
@@ -208,8 +261,14 @@
         public void onClick(View v) {
             if (v.getTag() instanceof BackStackEntry) {
                 BackStackEntry bse = (BackStackEntry) v.getTag();
-                mActivity.getFragmentManager().popBackStack(bse.getId(),
-                        bse == mTopEntry? FragmentManager.POP_BACK_STACK_INCLUSIVE : 0);
+                if (bse == mParentEntry) {
+                    if (mParentClickListener != null) {
+                        mParentClickListener.onClick(v);
+                    }
+                } else {
+                    mActivity.getFragmentManager().popBackStack(bse.getId(),
+                            bse == mTopEntry? FragmentManager.POP_BACK_STACK_INCLUSIVE : 0);
+                }
             }
         }
     };
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index d9039ab..7a186f3 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -1005,6 +1005,21 @@
             mFragmentBreadCrumbs.setActivity(this);
         }
         mFragmentBreadCrumbs.setTitle(title, shortTitle);
+        mFragmentBreadCrumbs.setParentTitle(null, null, null);
+    }
+
+    /**
+     * Should be called after onCreate to ensure that the breadcrumbs, if any, were created.
+     * This prepends a title to the fragment breadcrumbs and attaches a listener to any clicks
+     * on the parent entry.
+     * @param title the title for the breadcrumb
+     * @param shortTitle the short title for the breadcrumb
+     */
+    public void setParentTitle(CharSequence title, CharSequence shortTitle,
+            OnClickListener listener) {
+        if (mFragmentBreadCrumbs != null) {
+            mFragmentBreadCrumbs.setParentTitle(title, shortTitle, listener);
+        }
     }
 
     void setSelectedHeader(Header header) {