| /* |
| * 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; |
| } |
| } |