Add new DialogFragment class.

For all your Dialog needs.

Change-Id: I36c602ca253488d34a55c8f0be610b9752c33264
diff --git a/api/current.xml b/api/current.xml
index 27ab9f2..96ca9e9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -16410,6 +16410,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Dialog_NoFrame"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973972"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_InputMethod"
  type="int"
  transient="false"
@@ -21390,8 +21401,36 @@
  deprecated="not deprecated"
  visibility="public"
 >
+</method>
+<method name="popBackStack"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 <parameter name="name" type="java.lang.String">
 </parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="popBackStack"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
 </method>
 <method name="registerForContextMenu"
  return="void"
@@ -25835,6 +25874,211 @@
 </parameter>
 </method>
 </class>
+<class name="DialogFragment"
+ extends="android.app.Fragment"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.content.DialogInterface.OnCancelListener">
+</implements>
+<implements name="android.content.DialogInterface.OnDismissListener">
+</implements>
+<constructor name="DialogFragment"
+ type="android.app.DialogFragment"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="DialogFragment"
+ type="android.app.DialogFragment"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="style" type="int">
+</parameter>
+<parameter name="theme" type="int">
+</parameter>
+</constructor>
+<method name="dismiss"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCancelable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDialog"
+ return="android.app.Dialog"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTheme"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onCancel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dialog" type="android.content.DialogInterface">
+</parameter>
+</method>
+<method name="onCreateDialog"
+ return="android.app.Dialog"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onDismiss"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dialog" type="android.content.DialogInterface">
+</parameter>
+</method>
+<method name="setCancelable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cancelable" type="boolean">
+</parameter>
+</method>
+<method name="show"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
+<method name="show"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="transaction" type="android.app.FragmentTransaction">
+</parameter>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
+<field name="STYLE_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STYLE_NO_FRAME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STYLE_NO_INPUT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STYLE_NO_TITLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="ExpandableListActivity"
  extends="android.app.Activity"
  abstract="false"
@@ -26615,7 +26859,7 @@
 </parameter>
 </method>
 <method name="commit"
- return="void"
+ return="int"
  abstract="true"
  native="false"
  synchronized="false"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3298208..48d0d81 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2054,14 +2054,47 @@
     }
     
     /**
+     * Flag for {@link #popBackStack(String, int)}
+     * and {@link #popBackStack(int, int)}: If set, and the name or ID of
+     * a back stack entry has been supplied, then that entry will also be
+     * removed.  Otherwise, all entries up to but not including that entry
+     * will be removed
+     */
+    static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
+
+    /**
+     * Pop the top state off the back stack.  Returns true if there was one
+     * to pop, else false.
+     */
+    public boolean popBackStack() {
+        return popBackStack(null, 0);
+    }
+
+    /**
      * Pop the last fragment transition from the local activity's fragment
      * back stack.  If there is nothing to pop, false is returned.
      * @param name If non-null, this is the name of a previous back state
-     * to look for; if found, all states up to (but not including) that
-     * state will be popped.  If null, only the top state is popped.
+     * to look for; if found, all states up to that state will be popped.  The
+     * {@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}.
      */
-    public boolean popBackStack(String name) {
-        return mFragments.popBackStackState(mHandler, name);
+    public boolean popBackStack(String name, int flags) {
+        return mFragments.popBackStackState(mHandler, name, flags);
+    }
+
+    /**
+     * Pop all back stack states up to the one with the given identifier.
+     * @param id Identifier of the stated to be popped. If no identifier exists,
+     * false is returned.
+     * The identifier is the number returned by
+     * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.  The
+     * {@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}.
+     */
+    public boolean popBackStack(int id, int flags) {
+        return mFragments.popBackStackState(mHandler, id, flags);
     }
     
     /**
@@ -2070,7 +2103,7 @@
      * but you can override this to do whatever you want.
      */
     public void onBackPressed() {
-        if (!popBackStack(null)) {
+        if (!popBackStack()) {
             finish();
         }
     }
diff --git a/core/java/android/app/BackStackEntry.java b/core/java/android/app/BackStackEntry.java
index c958e26..7291438 100644
--- a/core/java/android/app/BackStackEntry.java
+++ b/core/java/android/app/BackStackEntry.java
@@ -27,6 +27,7 @@
     final int mTransition;
     final int mTransitionStyle;
     final String mName;
+    final int mIndex;
     
     public BackStackState(FragmentManager fm, BackStackEntry bse) {
         int numRemoved = 0;
@@ -58,6 +59,7 @@
         mTransition = bse.mTransition;
         mTransitionStyle = bse.mTransitionStyle;
         mName = bse.mName;
+        mIndex = bse.mIndex;
     }
     
     public BackStackState(Parcel in) {
@@ -65,6 +67,7 @@
         mTransition = in.readInt();
         mTransitionStyle = in.readInt();
         mName = in.readString();
+        mIndex = in.readInt();
     }
     
     public BackStackEntry instantiate(FragmentManager fm) {
@@ -90,6 +93,7 @@
         bse.mTransition = mTransition;
         bse.mTransitionStyle = mTransitionStyle;
         bse.mName = mName;
+        bse.mIndex = mIndex;
         return bse;
     }
     
@@ -102,6 +106,7 @@
         dest.writeInt(mTransition);
         dest.writeInt(mTransitionStyle);
         dest.writeString(mName);
+        dest.writeInt(mIndex);
     }
     
     public static final Parcelable.Creator<BackStackState> CREATOR
@@ -151,6 +156,7 @@
     boolean mAddToBackStack;
     String mName;
     boolean mCommitted;
+    int mIndex;
     
     public BackStackEntry(FragmentManager manager) {
         mManager = manager;
@@ -289,16 +295,28 @@
         return this;
     }
 
-    public void commit() {
+    public int commit() {
         if (mCommitted) throw new IllegalStateException("commit already called");
         if (FragmentManager.DEBUG) Log.v(TAG, "Commit: " + this);
         mCommitted = true;
+        if (mAddToBackStack) {
+            mIndex = mManager.allocBackStackIndex(this);
+        } else {
+            mIndex = -1;
+        }
         mManager.enqueueAction(this);
+        return mIndex;
     }
     
     public void run() {
         if (FragmentManager.DEBUG) Log.v(TAG, "Run: " + this);
         
+        if (mAddToBackStack) {
+            if (mIndex < 0) {
+                throw new IllegalStateException("addToBackStack() called after commit()");
+            }
+        }
+
         Op op = mHead;
         while (op != null) {
             switch (op.cmd) {
@@ -450,6 +468,11 @@
             mManager.mActivity.invalidateOptionsMenu();
             mManager.mNeedMenuInvalidate = false;
         }
+
+        if (mIndex >= 0) {
+            mManager.freeBackStackIndex(mIndex);
+            mIndex = -1;
+        }
     }
     
     public String getName() {
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
new file mode 100644
index 0000000..391f672
--- /dev/null
+++ b/core/java/android/app/DialogFragment.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package android.app;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+
+/**
+ * A fragment that displays a dialog window, floating on top of its
+ * activity's window.  This fragment contains a Dialog object, which it
+ * displays as appropriate based on the fragment's state.  Control of
+ * the dialog (deciding when to show, hide, dismiss it) should be done through
+ * the API here, not with direct calls on the dialog.
+ *
+ * <p>Implementations should override this class and implement
+ * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} to supply the
+ * content of the dialog.  Alternatively, they can override
+ * {@link #onCreateDialog(Bundle)} to create an entirely custom dialog, such
+ * as an AlertDialog, with its own content.
+ */
+public class DialogFragment extends Fragment
+        implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
+
+    /**
+     * Style for {@link #DialogFragment(int, int)} constructor: a basic,
+     * normal dialog.
+     */
+    public static final int STYLE_NORMAL = 0;
+
+    /**
+     * Style for {@link #DialogFragment(int, int)} constructor: don't include
+     * a title area.
+     */
+    public static final int STYLE_NO_TITLE = 1;
+
+    /**
+     * Style for {@link #DialogFragment(int, int)} constructor: don't draw
+     * any frame at all; the view hierarchy returned by {@link #onCreateView}
+     * is entirely responsible for drawing the dialog.
+     */
+    public static final int STYLE_NO_FRAME = 2;
+
+    /**
+     * Style for {@link #DialogFragment(int, int)} constructor: like
+     * {@link #STYLE_NO_FRAME}, but also disables all input to the dialog.
+     * The user can not touch it, and its window will not receive input focus.
+     */
+    public static final int STYLE_NO_INPUT = 3;
+
+    private static final String SAVED_DIALOG_STATE_TAG = "android:savedDialogState";
+    private static final String SAVED_STYLE = "android:style";
+    private static final String SAVED_THEME = "android:theme";
+    private static final String SAVED_CANCELABLE = "android:cancelable";
+    private static final String SAVED_BACK_STACK_ID = "android:backStackId";
+
+    int mStyle = STYLE_NORMAL;
+    int mTheme = 0;
+    boolean mCancelable = true;
+    int mBackStackId = -1;
+
+    Dialog mDialog;
+    boolean mDestroyed;
+
+    public DialogFragment() {
+    }
+
+    /**
+     * Constructor to customize the basic appearance and behavior of the
+     * fragment's dialog.  This can be used for some common dialog behaviors,
+     * taking care of selecting flags, theme, and other options for you.  The
+     * same effect can be achieve by manually setting Dialog and Window
+     * attributes yourself.
+     *
+     * @param style Selects a standard style: may be {@link #STYLE_NORMAL},
+     * {@link #STYLE_NO_TITLE}, {@link #STYLE_NO_FRAME}, or
+     * {@link #STYLE_NO_INPUT}.
+     * @param theme Optional custom theme.  If 0, an appropriate theme (based
+     * on the style) will be selected for you.
+     */
+    public DialogFragment(int style, int theme) {
+        mStyle = style;
+        if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) {
+            mTheme = android.R.style.Theme_Dialog_NoFrame;
+        }
+        if (theme != 0) {
+            mTheme = theme;
+        }
+    }
+
+    /**
+     * Display the dialog, adding the fragment to the given activity.  This
+     * is a convenience for explicitly creating a transaction, adding the
+     * fragment to it with the given tag, and committing it.  This does
+     * <em>not</em> add the transaction to the back stack.  When the fragment
+     * is dismissed, a new transaction will be executed to remove it from
+     * the activity.
+     * @param activity The activity this fragment will be added to.
+     * @param tag The tag for this fragment, as per
+     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
+     */
+    public void show(Activity activity, String tag) {
+        FragmentTransaction ft = activity.openFragmentTransaction();
+        ft.add(this, tag);
+        ft.commit();
+    }
+
+    /**
+     * Display the dialog, adding the fragment to the given activity using
+     * an existing transaction and then committing the transaction.
+     * @param activity The activity this fragment will be added to.
+     * @param transaction An existing transaction in which to add the fragment.
+     * @param tag The tag for this fragment, as per
+     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
+     * @return Returns the identifier of the committed transaction, as per
+     * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.
+     */
+    public int show(Activity activity, FragmentTransaction transaction, String tag) {
+        transaction.add(this, tag);
+        mBackStackId = transaction.commit();
+        return mBackStackId;
+    }
+
+    /**
+     * Dismiss the fragment and its dialog.  If the fragment was added to the
+     * back stack, all back stack state up to and including this entry will
+     * be popped.  Otherwise, a new transaction will be committed to remove
+     * the fragment.
+     */
+    public void dismiss() {
+        if (mDialog != null) {
+            mDialog.dismiss();
+        }
+        if (mBackStackId >= 0) {
+            getActivity().popBackStack(mBackStackId, Activity.POP_BACK_STACK_INCLUSIVE);
+            mBackStackId = -1;
+        } else {
+            FragmentTransaction ft = getActivity().openFragmentTransaction();
+            ft.remove(this);
+            ft.commit();
+        }
+    }
+
+    public Dialog getDialog() {
+        return mDialog;
+    }
+
+    public int getTheme() {
+        return mTheme;
+    }
+
+    public void setCancelable(boolean cancelable) {
+        mCancelable = cancelable;
+        if (mDialog != null) mDialog.setCancelable(cancelable);
+    }
+
+    public boolean getCancelable() {
+        return mCancelable;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            mStyle = savedInstanceState.getInt(SAVED_STYLE, mStyle);
+            mTheme = savedInstanceState.getInt(SAVED_THEME, mTheme);
+            mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, mCancelable);
+            mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, mBackStackId);
+        }
+    }
+
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new Dialog(getActivity(), getTheme());
+    }
+
+    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) {
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mDialog = onCreateDialog(savedInstanceState);
+        mDestroyed = false;
+        switch (mStyle) {
+            case STYLE_NO_INPUT:
+                mDialog.getWindow().addFlags(
+                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
+                        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+                // fall through...
+            case STYLE_NO_FRAME:
+            case STYLE_NO_TITLE:
+                mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        }
+        View view = getView();
+        if (view != null) {
+            if (view.getParent() != null) {
+                throw new IllegalStateException("DialogFragment can not be attached to a container view");
+            }
+            mDialog.setContentView(view);
+        }
+        mDialog.setOwnerActivity(getActivity());
+        mDialog.setCancelable(mCancelable);
+        mDialog.setOnCancelListener(this);
+        mDialog.setOnDismissListener(this);
+        if (savedInstanceState != null) {
+            Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG);
+            if (dialogState != null) {
+                mDialog.onRestoreInstanceState(dialogState);
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mDialog.show();
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        if (mDialog != null) {
+            Bundle dialogState = mDialog.onSaveInstanceState();
+            if (dialogState != null) {
+                outState.putBundle(SAVED_DIALOG_STATE_TAG, dialogState);
+            }
+        }
+        outState.putInt(SAVED_STYLE, mStyle);
+        outState.putInt(SAVED_THEME, mTheme);
+        outState.putBoolean(SAVED_CANCELABLE, mCancelable);
+        outState.putInt(SAVED_BACK_STACK_ID, mBackStackId);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        mDialog.hide();
+    }
+
+    /**
+     * Detach from list view.
+     */
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        mDestroyed = true;
+        mDialog.dismiss();
+        mDialog = null;
+    }
+}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 4f3043c..c0e757d 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -86,6 +86,10 @@
     ArrayList<Integer> mAvailIndices;
     ArrayList<BackStackEntry> mBackStack;
     
+    // Must be accessed while locked.
+    ArrayList<BackStackEntry> mBackStackIndices;
+    ArrayList<Integer> mAvailBackStackIndices;
+
     int mCurState = Fragment.INITIALIZING;
     Activity mActivity;
     
@@ -514,6 +518,62 @@
         }
     }
     
+    public int allocBackStackIndex(BackStackEntry bse) {
+        synchronized (this) {
+            if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
+                if (mBackStackIndices == null) {
+                    mBackStackIndices = new ArrayList<BackStackEntry>();
+                }
+                int index = mBackStackIndices.size();
+                if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
+                mBackStackIndices.add(bse);
+                return index;
+
+            } else {
+                int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
+                if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
+                mBackStackIndices.set(index, bse);
+                return index;
+            }
+        }
+    }
+
+    public void setBackStackIndex(int index, BackStackEntry bse) {
+        synchronized (this) {
+            if (mBackStackIndices == null) {
+                mBackStackIndices = new ArrayList<BackStackEntry>();
+            }
+            int N = mBackStackIndices.size();
+            if (index < N) {
+                if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
+                mBackStackIndices.set(index, bse);
+            } else {
+                while (N < index) {
+                    mBackStackIndices.add(null);
+                    if (mAvailBackStackIndices == null) {
+                        mAvailBackStackIndices = new ArrayList<Integer>();
+                    }
+                    if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
+                    mAvailBackStackIndices.add(N);
+                    N++;
+                }
+                if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
+                mBackStackIndices.add(bse);
+            }
+        }
+    }
+
+    public void freeBackStackIndex(int index) {
+        synchronized (this) {
+            mBackStackIndices.set(index, null);
+            if (mAvailBackStackIndices == null) {
+                mAvailBackStackIndices = new ArrayList<Integer>();
+            }
+            if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
+            mAvailBackStackIndices.add(index);
+        }
+    }
+
     /**
      * Only call from main thread!
      */
@@ -554,11 +614,22 @@
         mBackStack.add(state);
     }
     
-    public boolean popBackStackState(Handler handler, String name) {
+    public boolean popBackStackState(Handler handler, String name, int flags) {
+        return popBackStackState(handler, name, -1, flags);
+    }
+
+    public boolean popBackStackState(Handler handler, int id, int flags) {
+        if (id < 0) {
+            return false;
+        }
+        return popBackStackState(handler, null, id, flags);
+    }
+
+    boolean popBackStackState(Handler handler, String name, int id, int flags) {
         if (mBackStack == null) {
             return false;
         }
-        if (name == null) {
+        if (name == null && id < 0) {
             int last = mBackStack.size()-1;
             if (last < 0) {
                 return false;
@@ -576,11 +647,21 @@
             int index = mBackStack.size()-1;
             while (index >= 0) {
                 BackStackEntry bss = mBackStack.get(index);
-                if (name.equals(bss.getName())) {
+                if (name != null && name.equals(bss.getName())) {
                     break;
                 }
+                if (id >= 0 && id == bss.mIndex) {
+                    break;
+                }
+                index--;
             }
-            if (index < 0 || index == mBackStack.size()-1) {
+            if (index < 0) {
+                return false;
+            }
+            if ((flags&Activity.POP_BACK_STACK_INCLUSIVE) != 0) {
+                index--;
+            }
+            if (index == mBackStack.size()-1) {
                 return false;
             }
             final ArrayList<BackStackEntry> states
@@ -772,6 +853,9 @@
             for (int i=0; i<fms.mBackStack.length; i++) {
                 BackStackEntry bse = fms.mBackStack[i].instantiate(this);
                 mBackStack.add(bse);
+                if (bse.mIndex >= 0) {
+                    setBackStackIndex(bse.mIndex, bse);
+                }
             }
         } else {
             mBackStack = null;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 840f274..65cf85c 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -147,5 +147,15 @@
     public FragmentTransaction setTransitionStyle(int styleRes);
     
     public FragmentTransaction addToBackStack(String name);
-    public void commit();
+
+    /**
+     * Schedules a commit of this transaction.  Note that the commit does
+     * not happen immediately; it will be scheduled as work on the main thread
+     * to be done the next time that thread is ready.
+     *
+     * @return Returns the identifier of this transaction's back stack entry,
+     * if {@link #addToBackStack(String)} had been called.  Otherwise, returns
+     * a negative number.
+     */
+    public int commit();
 }
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index 73ef869..6e2f4b6 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -28,10 +28,10 @@
 import android.widget.TextView;
 
 /**
- * An fragment that displays a list of items by binding to a data source such as
+ * A fragment that displays a list of items by binding to a data source such as
  * an array or Cursor, and exposes event handlers when the user selects an item.
  * <p>
- * ListActivity hosts a {@link android.widget.ListView ListView} object that can
+ * ListFragment hosts a {@link android.widget.ListView ListView} object that can
  * be bound to different data sources, typically either an array or a Cursor
  * holding query results. Binding, screen layout, and row layout are discussed
  * in the following sections.
@@ -39,10 +39,10 @@
  * <strong>Screen Layout</strong>
  * </p>
  * <p>
- * ListActivity has a default layout that consists of a single list view.
+ * ListFragment has a default layout that consists of a single list view.
  * However, if you desire, you can customize the fragment layout by returning
  * your own view hierarchy from {@link #onCreateView}.
- * To do this, your view hierarchy MUST contain a ListView object with the
+ * To do this, your view hierarchy <em>must</em> contain a ListView object with the
  * id "@android:id/list" (or {@link android.R.id#list} if it's in code)
  * <p>
  * Optionally, your view hierarchy can contain another view object of any type to
@@ -50,7 +50,7 @@
  * id "android:empty". Note that when an empty view is present, the list view
  * will be hidden when there is no data to display.
  * <p>
- * The following code demonstrates an (ugly) custom lisy layout. It has a list
+ * The following code demonstrates an (ugly) custom list layout. It has a list
  * with a green background, and an alternate red "no data" message.
  * </p>
  *
@@ -134,6 +134,13 @@
  * and {@link android.widget.SimpleCursorAdapter SimpleCursorAdapter} for Cursor
  * query results.
  * </p>
+ * <p>
+ * You <b>must</b> use
+ * {@link #setListAdapter(ListAdapter) ListFragment.setListAdapter()} to
+ * associate the list with an adapter.  Do not directly call
+ * {@link ListView#setAdapter(ListAdapter) ListView.setAdapter()} or else
+ * important initialization will be skipped.
+ * </p>
  *
  * @see #setListAdapter
  * @see android.widget.ListView
@@ -160,6 +167,7 @@
     TextView mStandardEmptyView;
     View mProgressContainer;
     View mListContainer;
+    boolean mSetEmptyText;
     boolean mListShown;
 
     public ListFragment() {
@@ -280,7 +288,11 @@
         if (mStandardEmptyView == null) {
             throw new IllegalStateException("Can't be used with a custom content view");
         }
-        mList.setEmptyView(mStandardEmptyView);
+        mStandardEmptyView.setText(text);
+        if (!mSetEmptyText) {
+            mList.setEmptyView(mStandardEmptyView);
+            mSetEmptyText = true;
+        }
     }
     
     /**
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d0be554..34dd46c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1314,6 +1314,7 @@
   <public type="style" name="Theme.WithActionBar" />
   <public type="style" name="Widget.Spinner.DropDown" />
   <public type="style" name="Widget.ActionButton" />
+  <public type="style" name="Theme.Dialog.NoFrame" />
 
   <!-- Standard content view for a {@link android.app.ListFragment}.
        If you are implementing a subclass of ListFragment with your
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 2dfe9ab..bce0e02 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -426,13 +426,25 @@
         <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
     </style>
 
+    <!-- Variation of Theme.Dialog that does not include a frame (or background).
+         The view hierarchy of the dialog is responsible for drawing all of
+         its pixels. -->
+    <style name="Theme.Dialog.NoFrame">
+        <item name="windowBackground">@android:color/transparent</item>
+        <item name="android:windowFrame">@null</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="android:windowAnimationStyle">@null</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
     <!-- Default theme for alert dialog windows, which is used by the
          {@link android.app.AlertDialog} class.  This is basically a dialog
          but sets the background to empty so it can do two-tone backgrounds. -->
     <style name="Theme.Dialog.Alert">
         <item name="windowBackground">@android:color/transparent</item>
         <item name="windowTitleStyle">@android:style/DialogWindowTitle</item>
-        <item name="windowIsFloating">true</item>
         <item name="windowContentOverlay">@null</item>
     </style>