19daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org/*
29daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org * Copyright (C) 2011 The Android Open Source Project
39daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org *
49daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org * Licensed under the Apache License, Version 2.0 (the "License");
59daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org * you may not use this file except in compliance with the License.
69daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org * You may obtain a copy of the License at
79daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org *
89daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org *      http://www.apache.org/licenses/LICENSE-2.0
99daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org *
101a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * Unless required by applicable law or agreed to in writing, software
111a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * distributed under the License is distributed on an "AS IS" BASIS,
128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org * See the License for the specific language governing permissions and
141a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * limitations under the License.
151a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org */
169daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org
179daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.orgpackage android.support.v4.app;
184cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org
199daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.orgimport android.app.Activity;
20ae761f7545d8ebf181d220169afac2056b057b8ccommit-bot@chromium.orgimport android.app.Dialog;
211a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.orgimport android.content.Context;
2268400767be5f72e4b9750ccc8bcf0078d42869a7senorblanco@chromium.orgimport android.content.DialogInterface;
236776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.orgimport android.os.Bundle;
24f2f8f3a43c5d7c7bd66afc6d9097ad5968df1596commit-bot@chromium.orgimport android.support.annotation.IntDef;
25f2f8f3a43c5d7c7bd66afc6d9097ad5968df1596commit-bot@chromium.orgimport android.support.annotation.NonNull;
26f2f8f3a43c5d7c7bd66afc6d9097ad5968df1596commit-bot@chromium.orgimport android.support.annotation.Nullable;
27b295fb6ff3222453912dfcb7a1ea5184d40014b5senorblanco@chromium.orgimport android.support.annotation.StyleRes;
28f2f8f3a43c5d7c7bd66afc6d9097ad5968df1596commit-bot@chromium.orgimport android.view.LayoutInflater;
294cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.orgimport android.view.View;
301a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.orgimport android.view.ViewGroup;
311a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.orgimport android.view.Window;
3268400767be5f72e4b9750ccc8bcf0078d42869a7senorblanco@chromium.orgimport android.view.WindowManager;
331a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
344cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.orgimport java.lang.annotation.Retention;
359daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.orgimport java.lang.annotation.RetentionPolicy;
366776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org
376776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org/**
381a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * Static library support version of the framework's {@link android.app.DialogFragment}.
391a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * Used to write apps that run on platforms prior to Android 3.0.  When running
404cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org * on Android 3.0 or above, this implementation is still used; it does not try
411a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * to switch to the framework's implementation.  See the framework SDK
421a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org * documentation for a class overview.
431a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org */
441a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.orgpublic class DialogFragment extends Fragment
45118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org        implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
461a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org
471a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    /** @hide */
481a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    @IntDef({STYLE_NORMAL, STYLE_NO_TITLE, STYLE_NO_FRAME, STYLE_NO_INPUT})
491a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    @Retention(RetentionPolicy.SOURCE)
50cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    private @interface DialogStyle {}
51cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org
52cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    /**
531a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org     * Style for {@link #setStyle(int, int)}: a basic,
541a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org     * normal dialog.
551a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org     */
566776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    public static final int STYLE_NORMAL = 0;
576776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org
58e09244d463695cd9d2b089794ca18f59f1e4a621senorblanco@chromium.org    /**
594cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org     * Style for {@link #setStyle(int, int)}: don't include
60e09244d463695cd9d2b089794ca18f59f1e4a621senorblanco@chromium.org     * a title area.
611a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org     */
626776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    public static final int STYLE_NO_TITLE = 1;
636776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org
641a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org    /**
659daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * Style for {@link #setStyle(int, int)}: don't draw
669daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * any frame at all; the view hierarchy returned by {@link #onCreateView}
679daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * is entirely responsible for drawing the dialog.
68336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org     */
69336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    public static final int STYLE_NO_FRAME = 2;
70336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org
71336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    /**
72336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org     * Style for {@link #setStyle(int, int)}: like
73336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org     * {@link #STYLE_NO_FRAME}, but also disables all input to the dialog.
74c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org     * The user can not touch it, and its window will not receive input focus.
75336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org     */
76c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    public static final int STYLE_NO_INPUT = 3;
77336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org
78336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    private static final String SAVED_DIALOG_STATE_TAG = "android:savedDialogState";
799daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    private static final String SAVED_STYLE = "android:style";
80c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    private static final String SAVED_THEME = "android:theme";
819daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    private static final String SAVED_CANCELABLE = "android:cancelable";
829daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    private static final String SAVED_SHOWS_DIALOG = "android:showsDialog";
839daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    private static final String SAVED_BACK_STACK_ID = "android:backStackId";
8406342a2666012f5d27faa7c2e230ae54f2dff311senorblanco@chromium.org
8506342a2666012f5d27faa7c2e230ae54f2dff311senorblanco@chromium.org    int mStyle = STYLE_NORMAL;
8606342a2666012f5d27faa7c2e230ae54f2dff311senorblanco@chromium.org    int mTheme = 0;
8729ac34ee526578fb0a01cd2d0c23c23e6a823d82senorblanco@chromium.org    boolean mCancelable = true;
8829ac34ee526578fb0a01cd2d0c23c23e6a823d82senorblanco@chromium.org    boolean mShowsDialog = true;
8929ac34ee526578fb0a01cd2d0c23c23e6a823d82senorblanco@chromium.org    int mBackStackId = -1;
9006342a2666012f5d27faa7c2e230ae54f2dff311senorblanco@chromium.org
919daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    Dialog mDialog;
929daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    boolean mViewDestroyed;
939daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org    boolean mDismissed;
949fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    boolean mShownByMe;
959fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
969fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    public DialogFragment() {
979fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
9824e06d5244ae96e440410e1d76e039983b2efac9senorblanco
999fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    /**
1009fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed     * Call to customize the basic appearance and behavior of the
1018b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org     * fragment's dialog.  This can be used for some common dialog behaviors,
1029daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * taking care of selecting flags, theme, and other options for you.  The
1039daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * same effect can be achieve by manually setting Dialog and Window
1049daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * attributes yourself.  Calling this after the fragment's Dialog is
1059daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * created will have no effect.
1061a4fb70c8a04db2d92ec821555f91218a989031dcommit-bot@chromium.org     *
10724e06d5244ae96e440410e1d76e039983b2efac9senorblanco     * @param style Selects a standard style: may be {@link #STYLE_NORMAL},
10824e06d5244ae96e440410e1d76e039983b2efac9senorblanco     * {@link #STYLE_NO_TITLE}, {@link #STYLE_NO_FRAME}, or
1099daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * {@link #STYLE_NO_INPUT}.
1109daf96afb34313842d8d2c4abca73d954d2e9005senorblanco@chromium.org     * @param theme Optional custom theme.  If 0, an appropriate theme (based
111f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips     * on the style) will be selected for you.
112f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips     */
113f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    public void setStyle(@DialogStyle int style, @StyleRes int theme) {
114f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        mStyle = style;
115f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) {
116f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips            mTheme = android.R.style.Theme_Panel;
117f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        }
118f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        if (theme != 0) {
119f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips            mTheme = theme;
120f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips        }
121f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    }
122f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
123    /**
124     * Display the dialog, adding the fragment to the given FragmentManager.  This
125     * is a convenience for explicitly creating a transaction, adding the
126     * fragment to it with the given tag, and committing it.  This does
127     * <em>not</em> add the transaction to the back stack.  When the fragment
128     * is dismissed, a new transaction will be executed to remove it from
129     * the activity.
130     * @param manager The FragmentManager this fragment will be added to.
131     * @param tag The tag for this fragment, as per
132     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
133     */
134    public void show(FragmentManager manager, String tag) {
135        mDismissed = false;
136        mShownByMe = true;
137        FragmentTransaction ft = manager.beginTransaction();
138        ft.add(this, tag);
139        ft.commit();
140    }
141
142    /**
143     * Display the dialog, adding the fragment using an existing transaction
144     * and then committing the transaction.
145     * @param transaction An existing transaction in which to add the fragment.
146     * @param tag The tag for this fragment, as per
147     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
148     * @return Returns the identifier of the committed transaction, as per
149     * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.
150     */
151    public int show(FragmentTransaction transaction, String tag) {
152        mDismissed = false;
153        mShownByMe = true;
154        transaction.add(this, tag);
155        mViewDestroyed = false;
156        mBackStackId = transaction.commit();
157        return mBackStackId;
158    }
159
160    /**
161     * Dismiss the fragment and its dialog.  If the fragment was added to the
162     * back stack, all back stack state up to and including this entry will
163     * be popped.  Otherwise, a new transaction will be committed to remove
164     * the fragment.
165     */
166    public void dismiss() {
167        dismissInternal(false);
168    }
169
170    /**
171     * Version of {@link #dismiss()} that uses
172     * {@link FragmentTransaction#commitAllowingStateLoss()
173     * FragmentTransaction.commitAllowingStateLoss()}. See linked
174     * documentation for further details.
175     */
176    public void dismissAllowingStateLoss() {
177        dismissInternal(true);
178    }
179
180    void dismissInternal(boolean allowStateLoss) {
181        if (mDismissed) {
182            return;
183        }
184        mDismissed = true;
185        mShownByMe = false;
186        if (mDialog != null) {
187            mDialog.dismiss();
188            mDialog = null;
189        }
190        mViewDestroyed = true;
191        if (mBackStackId >= 0) {
192            getFragmentManager().popBackStack(mBackStackId,
193                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
194            mBackStackId = -1;
195        } else {
196            FragmentTransaction ft = getFragmentManager().beginTransaction();
197            ft.remove(this);
198            if (allowStateLoss) {
199                ft.commitAllowingStateLoss();
200            } else {
201                ft.commit();
202            }
203        }
204    }
205
206    public Dialog getDialog() {
207        return mDialog;
208    }
209
210    @StyleRes
211    public int getTheme() {
212        return mTheme;
213    }
214
215    /**
216     * Control whether the shown Dialog is cancelable.  Use this instead of
217     * directly calling {@link Dialog#setCancelable(boolean)
218     * Dialog.setCancelable(boolean)}, because DialogFragment needs to change
219     * its behavior based on this.
220     *
221     * @param cancelable If true, the dialog is cancelable.  The default
222     * is true.
223     */
224    public void setCancelable(boolean cancelable) {
225        mCancelable = cancelable;
226        if (mDialog != null) mDialog.setCancelable(cancelable);
227    }
228
229    /**
230     * Return the current value of {@link #setCancelable(boolean)}.
231     */
232    public boolean isCancelable() {
233        return mCancelable;
234    }
235
236    /**
237     * Controls whether this fragment should be shown in a dialog.  If not
238     * set, no Dialog will be created in {@link #onActivityCreated(Bundle)},
239     * and the fragment's view hierarchy will thus not be added to it.  This
240     * allows you to instead use it as a normal fragment (embedded inside of
241     * its activity).
242     *
243     * <p>This is normally set for you based on whether the fragment is
244     * associated with a container view ID passed to
245     * {@link FragmentTransaction#add(int, Fragment) FragmentTransaction.add(int, Fragment)}.
246     * If the fragment was added with a container, setShowsDialog will be
247     * initialized to false; otherwise, it will be true.
248     *
249     * @param showsDialog If true, the fragment will be displayed in a Dialog.
250     * If false, no Dialog will be created and the fragment's view hierarchly
251     * left undisturbed.
252     */
253    public void setShowsDialog(boolean showsDialog) {
254        mShowsDialog = showsDialog;
255    }
256
257    /**
258     * Return the current value of {@link #setShowsDialog(boolean)}.
259     */
260    public boolean getShowsDialog() {
261        return mShowsDialog;
262    }
263
264    @Override
265    public void onAttach(Activity activity) {
266        super.onAttach(activity);
267        if (!mShownByMe) {
268            // If not explicitly shown through our API, take this as an
269            // indication that the dialog is no longer dismissed.
270            mDismissed = false;
271        }
272    }
273
274    @Override
275    public void onDetach() {
276        super.onDetach();
277        if (!mShownByMe && !mDismissed) {
278            // The fragment was not shown by a direct call here, it is not
279            // dismissed, and now it is being detached...  well, okay, thou
280            // art now dismissed.  Have fun.
281            mDismissed = true;
282        }
283    }
284
285    @Override
286    public void onCreate(@Nullable Bundle savedInstanceState) {
287        super.onCreate(savedInstanceState);
288
289        mShowsDialog = mContainerId == 0;
290
291        if (savedInstanceState != null) {
292            mStyle = savedInstanceState.getInt(SAVED_STYLE, STYLE_NORMAL);
293            mTheme = savedInstanceState.getInt(SAVED_THEME, 0);
294            mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, true);
295            mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);
296            mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1);
297        }
298
299    }
300
301    /** @hide */
302    @Override
303    public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
304        if (!mShowsDialog) {
305            return super.getLayoutInflater(savedInstanceState);
306        }
307
308        mDialog = onCreateDialog(savedInstanceState);
309
310        if (mDialog != null) {
311            setupDialog(mDialog, mStyle);
312
313            return (LayoutInflater) mDialog.getContext().getSystemService(
314                    Context.LAYOUT_INFLATER_SERVICE);
315        }
316        return (LayoutInflater) mHost.getContext().getSystemService(
317                Context.LAYOUT_INFLATER_SERVICE);
318    }
319
320    /** @hide */
321    public void setupDialog(Dialog dialog, int style) {
322        switch (style) {
323            case STYLE_NO_INPUT:
324                dialog.getWindow().addFlags(
325                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
326                                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
327                // fall through...
328            case STYLE_NO_FRAME:
329            case STYLE_NO_TITLE:
330                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
331        }
332    }
333
334    /**
335     * Override to build your own custom Dialog container.  This is typically
336     * used to show an AlertDialog instead of a generic Dialog; when doing so,
337     * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} does not need
338     * to be implemented since the AlertDialog takes care of its own content.
339     *
340     * <p>This method will be called after {@link #onCreate(Bundle)} and
341     * before {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.  The
342     * default implementation simply instantiates and returns a {@link Dialog}
343     * class.
344     *
345     * <p><em>Note: DialogFragment own the {@link Dialog#setOnCancelListener
346     * Dialog.setOnCancelListener} and {@link Dialog#setOnDismissListener
347     * Dialog.setOnDismissListener} callbacks.  You must not set them yourself.</em>
348     * To find out about these events, override {@link #onCancel(DialogInterface)}
349     * and {@link #onDismiss(DialogInterface)}.</p>
350     *
351     * @param savedInstanceState The last saved instance state of the Fragment,
352     * or null if this is a freshly created Fragment.
353     *
354     * @return Return a new Dialog instance to be displayed by the Fragment.
355     */
356    @NonNull
357    public Dialog onCreateDialog(Bundle savedInstanceState) {
358        return new Dialog(getActivity(), getTheme());
359    }
360
361    public void onCancel(DialogInterface dialog) {
362    }
363
364    public void onDismiss(DialogInterface dialog) {
365        if (!mViewDestroyed) {
366            // Note: we need to use allowStateLoss, because the dialog
367            // dispatches this asynchronously so we can receive the call
368            // after the activity is paused.  Worst case, when the user comes
369            // back to the activity they see the dialog again.
370            dismissInternal(true);
371        }
372    }
373
374    @Override
375    public void onActivityCreated(Bundle savedInstanceState) {
376        super.onActivityCreated(savedInstanceState);
377
378        if (!mShowsDialog) {
379            return;
380        }
381
382        View view = getView();
383        if (view != null) {
384            if (view.getParent() != null) {
385                throw new IllegalStateException("DialogFragment can not be attached to a container view");
386            }
387            mDialog.setContentView(view);
388        }
389        mDialog.setOwnerActivity(getActivity());
390        mDialog.setCancelable(mCancelable);
391        mDialog.setOnCancelListener(this);
392        mDialog.setOnDismissListener(this);
393        if (savedInstanceState != null) {
394            Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG);
395            if (dialogState != null) {
396                mDialog.onRestoreInstanceState(dialogState);
397            }
398        }
399    }
400
401    @Override
402    public void onStart() {
403        super.onStart();
404        if (mDialog != null) {
405            mViewDestroyed = false;
406            mDialog.show();
407        }
408    }
409
410    @Override
411    public void onSaveInstanceState(Bundle outState) {
412        super.onSaveInstanceState(outState);
413        if (mDialog != null) {
414            Bundle dialogState = mDialog.onSaveInstanceState();
415            if (dialogState != null) {
416                outState.putBundle(SAVED_DIALOG_STATE_TAG, dialogState);
417            }
418        }
419        if (mStyle != STYLE_NORMAL) {
420            outState.putInt(SAVED_STYLE, mStyle);
421        }
422        if (mTheme != 0) {
423            outState.putInt(SAVED_THEME, mTheme);
424        }
425        if (!mCancelable) {
426            outState.putBoolean(SAVED_CANCELABLE, mCancelable);
427        }
428        if (!mShowsDialog) {
429            outState.putBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);
430        }
431        if (mBackStackId != -1) {
432            outState.putInt(SAVED_BACK_STACK_ID, mBackStackId);
433        }
434    }
435
436    @Override
437    public void onStop() {
438        super.onStop();
439        if (mDialog != null) {
440            mDialog.hide();
441        }
442    }
443
444    /**
445     * Remove dialog.
446     */
447    @Override
448    public void onDestroyView() {
449        super.onDestroyView();
450        if (mDialog != null) {
451            // Set removed here because this dismissal is just to hide
452            // the dialog -- we don't want this to cause the fragment to
453            // actually be removed.
454            mViewDestroyed = true;
455            mDialog.dismiss();
456            mDialog = null;
457        }
458    }
459}
460