Merge "Stash dialog info when constructing pref dialogs" into mnc-ub-dev am: 30cf890c76
am: 1870114cf6

* commit '1870114cf6c25748ab66dace4e639c812f43d875':
  Stash dialog info when constructing pref dialogs
diff --git a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
index 498b874..4f64876 100644
--- a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
@@ -17,14 +17,19 @@
 package android.support.v14.preference;
 
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.v7.preference.EditTextPreference;
 import android.view.View;
 import android.widget.EditText;
 
 public class EditTextPreferenceDialogFragment extends PreferenceDialogFragment {
 
+    private static final String SAVE_STATE_TEXT = "EditTextPreferenceDialogFragment.text";
+
     private EditText mEditText;
 
+    private CharSequence mText;
+
     public static EditTextPreferenceDialogFragment newInstance(String key) {
         final EditTextPreferenceDialogFragment
                 fragment = new EditTextPreferenceDialogFragment();
@@ -35,6 +40,22 @@
     }
 
     @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState == null) {
+            mText = getEditTextPreference().getText();
+        } else {
+            mText = savedInstanceState.getCharSequence(SAVE_STATE_TEXT);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putCharSequence(SAVE_STATE_TEXT, mText);
+    }
+
+    @Override
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
 
@@ -45,7 +66,7 @@
                     " @android:id/edit");
         }
 
-        mEditText.setText(getEditTextPreference().getText());
+        mEditText.setText(mText);
     }
 
     private EditTextPreference getEditTextPreference() {
diff --git a/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
index c4e922c..6b385d8 100644
--- a/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
@@ -19,11 +19,19 @@
 import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.v7.preference.ListPreference;
 
 public class ListPreferenceDialogFragment extends PreferenceDialogFragment {
 
+    private static final String SAVE_STATE_INDEX = "ListPreferenceDialogFragment.index";
+    private static final String SAVE_STATE_ENTRIES = "ListPreferenceDialogFragment.entries";
+    private static final String SAVE_STATE_ENTRY_VALUES =
+            "ListPreferenceDialogFragment.entryValues";
+
     private int mClickedDialogEntryIndex;
+    private CharSequence[] mEntries;
+    private CharSequence[] mEntryValues;
 
     public static ListPreferenceDialogFragment newInstance(String key) {
         final ListPreferenceDialogFragment fragment = new ListPreferenceDialogFragment();
@@ -33,6 +41,35 @@
         return fragment;
     }
 
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState == null) {
+            final ListPreference preference = getListPreference();
+
+            if (preference.getEntries() == null || preference.getEntryValues() == null) {
+                throw new IllegalStateException(
+                        "ListPreference requires an entries array and an entryValues array.");
+            }
+
+            mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
+            mEntries = preference.getEntries();
+            mEntryValues = preference.getEntryValues();
+        } else {
+            mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0);
+            mEntries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES);
+            mEntryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex);
+        outState.putCharSequenceArray(SAVE_STATE_ENTRIES, mEntries);
+        outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
+    }
+
     private ListPreference getListPreference() {
         return (ListPreference) getPreference();
     }
@@ -41,15 +78,7 @@
     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
         super.onPrepareDialogBuilder(builder);
 
-        final ListPreference preference = getListPreference();
-
-        if (preference.getEntries() == null || preference.getEntryValues() == null) {
-            throw new IllegalStateException(
-                    "ListPreference requires an entries array and an entryValues array.");
-        }
-
-        mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
-        builder.setSingleChoiceItems(preference.getEntries(), mClickedDialogEntryIndex,
+        builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
                 new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int which) {
                         mClickedDialogEntryIndex = which;
@@ -75,9 +104,8 @@
     @Override
     public void onDialogClosed(boolean positiveResult) {
         final ListPreference preference = getListPreference();
-        if (positiveResult && mClickedDialogEntryIndex >= 0 &&
-                preference.getEntryValues() != null) {
-            String value = preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+        if (positiveResult && mClickedDialogEntryIndex >= 0) {
+            String value = mEntryValues[mClickedDialogEntryIndex].toString();
             if (preference.callChangeListener(value)) {
                 preference.setValue(value);
             }
diff --git a/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
index ec46aac..5b585bc 100644
--- a/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
@@ -19,14 +19,27 @@
 import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
 public class MultiSelectListPreferenceDialogFragment extends PreferenceDialogFragment {
 
+    private static final String SAVE_STATE_VALUES =
+            "MultiSelectListPreferenceDialogFragment.values";
+    private static final String SAVE_STATE_CHANGED =
+            "MultiSelectListPreferenceDialogFragment.changed";
+    private static final String SAVE_STATE_ENTRIES =
+            "MultiSelectListPreferenceDialogFragment.entries";
+    private static final String SAVE_STATE_ENTRY_VALUES =
+            "MultiSelectListPreferenceDialogFragment.entryValues";
+
     private Set<String> mNewValues = new HashSet<>();
     private boolean mPreferenceChanged;
+    private CharSequence[] mEntries;
+    private CharSequence[] mEntryValues;
 
     public static MultiSelectListPreferenceDialogFragment newInstance(String key) {
         final MultiSelectListPreferenceDialogFragment fragment =
@@ -37,6 +50,42 @@
         return fragment;
     }
 
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            final MultiSelectListPreference preference = getListPreference();
+
+            if (preference.getEntries() == null || preference.getEntryValues() == null) {
+                throw new IllegalStateException(
+                        "MultiSelectListPreference requires an entries array and " +
+                                "an entryValues array.");
+            }
+
+            mNewValues.clear();
+            mNewValues.addAll(preference.getValues());
+            mPreferenceChanged = false;
+            mEntries = preference.getEntries();
+            mEntryValues = preference.getEntryValues();
+        } else {
+            mNewValues.clear();
+            mNewValues.addAll(savedInstanceState.getStringArrayList(SAVE_STATE_VALUES));
+            mPreferenceChanged = savedInstanceState.getBoolean(SAVE_STATE_CHANGED, false);
+            mEntries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES);
+            mEntryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putStringArrayList(SAVE_STATE_VALUES, new ArrayList<>(mNewValues));
+        outState.putBoolean(SAVE_STATE_CHANGED, mPreferenceChanged);
+        outState.putCharSequenceArray(SAVE_STATE_ENTRIES, mEntries);
+        outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
+    }
+
     private MultiSelectListPreference getListPreference() {
         return (MultiSelectListPreference) getPreference();
     }
@@ -45,29 +94,23 @@
     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
         super.onPrepareDialogBuilder(builder);
 
-        final MultiSelectListPreference preference = getListPreference();
-
-        if (preference.getEntries() == null || preference.getEntryValues() == null) {
-            throw new IllegalStateException(
-                    "MultiSelectListPreference requires an entries array and " +
-                            "an entryValues array.");
+        final int entryCount = mEntryValues.length;
+        final boolean[] checkedItems = new boolean[entryCount];
+        for (int i = 0; i < entryCount; i++) {
+            checkedItems[i] = mNewValues.contains(mEntryValues[i].toString());
         }
-
-        boolean[] checkedItems = preference.getSelectedItems();
-        builder.setMultiChoiceItems(preference.getEntries(), checkedItems,
+        builder.setMultiChoiceItems(mEntries, checkedItems,
                 new DialogInterface.OnMultiChoiceClickListener() {
                     public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                         if (isChecked) {
                             mPreferenceChanged |= mNewValues.add(
-                                    preference.getEntryValues()[which].toString());
+                                    mEntryValues[which].toString());
                         } else {
                             mPreferenceChanged |= mNewValues.remove(
-                                    preference.getEntryValues()[which].toString());
+                                    mEntryValues[which].toString());
                         }
                     }
                 });
-        mNewValues.clear();
-        mNewValues.addAll(preference.getValues());
     }
 
     @Override
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java
index 8f5dd64..48b404e 100644
--- a/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java
@@ -22,7 +22,12 @@
 import android.app.Fragment;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.v7.preference.DialogPreference;
 import android.text.TextUtils;
@@ -32,13 +37,35 @@
 import android.view.WindowManager;
 import android.widget.TextView;
 
+/**
+ * Abstract base class which presents a dialog associated with a
+ * {@link android.support.v7.preference.DialogPreference}. Since the preference object may
+ * not be available during fragment re-creation, the necessary information for displaying the dialog
+ * is read once during the initial call to {@link #onCreate(Bundle)} and saved/restored in the saved
+ * instance state. Custom subclasses should also follow this pattern.
+ */
 public abstract class PreferenceDialogFragment extends DialogFragment implements
         DialogInterface.OnClickListener {
 
     protected static final String ARG_KEY = "key";
 
+    private static final String SAVE_STATE_TITLE = "PreferenceDialogFragment.title";
+    private static final String SAVE_STATE_POSITIVE_TEXT = "PreferenceDialogFragment.positiveText";
+    private static final String SAVE_STATE_NEGATIVE_TEXT = "PreferenceDialogFragment.negativeText";
+    private static final String SAVE_STATE_MESSAGE = "PreferenceDialogFragment.message";
+    private static final String SAVE_STATE_LAYOUT = "PreferenceDialogFragment.layout";
+    private static final String SAVE_STATE_ICON = "PreferenceDialogFragment.icon";
+
     private DialogPreference mPreference;
 
+    private CharSequence mDialogTitle;
+    private CharSequence mPositiveButtonText;
+    private CharSequence mNegativeButtonText;
+    private CharSequence mDialogMessage;
+    private @LayoutRes int mDialogLayoutRes;
+
+    private BitmapDrawable mDialogIcon;
+
     /** Which button was clicked. */
     private int mWhichButtonClicked;
 
@@ -56,7 +83,50 @@
                 (DialogPreference.TargetFragment) rawFragment;
 
         final String key = getArguments().getString(ARG_KEY);
-        mPreference = (DialogPreference) fragment.findPreference(key);
+        if (savedInstanceState == null) {
+            mPreference = (DialogPreference) fragment.findPreference(key);
+            mDialogTitle = mPreference.getDialogTitle();
+            mPositiveButtonText = mPreference.getPositiveButtonText();
+            mNegativeButtonText = mPreference.getNegativeButtonText();
+            mDialogMessage = mPreference.getDialogMessage();
+            mDialogLayoutRes = mPreference.getDialogLayoutResource();
+
+            final Drawable icon = mPreference.getDialogIcon();
+            if (icon == null || icon instanceof BitmapDrawable) {
+                mDialogIcon = (BitmapDrawable) icon;
+            } else {
+                final Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
+                        icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+                final Canvas canvas = new Canvas(bitmap);
+                icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+                icon.draw(canvas);
+                mDialogIcon = new BitmapDrawable(getResources(), bitmap);
+            }
+        } else {
+            mDialogTitle = savedInstanceState.getCharSequence(SAVE_STATE_TITLE);
+            mPositiveButtonText = savedInstanceState.getCharSequence(SAVE_STATE_POSITIVE_TEXT);
+            mNegativeButtonText = savedInstanceState.getCharSequence(SAVE_STATE_NEGATIVE_TEXT);
+            mDialogMessage = savedInstanceState.getCharSequence(SAVE_STATE_MESSAGE);
+            mDialogLayoutRes = savedInstanceState.getInt(SAVE_STATE_LAYOUT, 0);
+            final Bitmap bitmap = savedInstanceState.getParcelable(SAVE_STATE_ICON);
+            if (bitmap != null) {
+                mDialogIcon = new BitmapDrawable(getResources(), bitmap);
+            }
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+
+        outState.putCharSequence(SAVE_STATE_TITLE, mDialogTitle);
+        outState.putCharSequence(SAVE_STATE_POSITIVE_TEXT, mPositiveButtonText);
+        outState.putCharSequence(SAVE_STATE_NEGATIVE_TEXT, mNegativeButtonText);
+        outState.putCharSequence(SAVE_STATE_MESSAGE, mDialogMessage);
+        outState.putInt(SAVE_STATE_LAYOUT, mDialogLayoutRes);
+        if (mDialogIcon != null) {
+            outState.putParcelable(SAVE_STATE_ICON, mDialogIcon.getBitmap());
+        }
     }
 
     @Override
@@ -66,17 +136,17 @@
         mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
 
         final AlertDialog.Builder builder = new AlertDialog.Builder(context)
-                .setTitle(mPreference.getDialogTitle())
-                .setIcon(mPreference.getDialogIcon())
-                .setPositiveButton(mPreference.getPositiveButtonText(), this)
-                .setNegativeButton(mPreference.getNegativeButtonText(), this);
+                .setTitle(mDialogTitle)
+                .setIcon(mDialogIcon)
+                .setPositiveButton(mPositiveButtonText, this)
+                .setNegativeButton(mNegativeButtonText, this);
 
         View contentView = onCreateDialogView(context);
         if (contentView != null) {
             onBindDialogView(contentView);
             builder.setView(contentView);
         } else {
-            builder.setMessage(mPreference.getDialogMessage());
+            builder.setMessage(mDialogMessage);
         }
 
         onPrepareDialogBuilder(builder);
@@ -92,12 +162,18 @@
 
     /**
      * Get the preference that requested this dialog. Available after {@link #onCreate(Bundle)} has
-     * been called.
+     * been called on the {@link PreferenceFragment} which launched this dialog.
      *
      * @return The {@link DialogPreference} associated with this
      * dialog.
      */
     public DialogPreference getPreference() {
+        if (mPreference == null) {
+            final String key = getArguments().getString(ARG_KEY);
+            final DialogPreference.TargetFragment fragment =
+                    (DialogPreference.TargetFragment) getTargetFragment();
+            mPreference = (DialogPreference) fragment.findPreference(key);
+        }
         return mPreference;
     }
 
@@ -137,7 +213,7 @@
      * @see DialogPreference#setLayoutResource(int)
      */
     protected View onCreateDialogView(Context context) {
-        final int resId = mPreference.getDialogLayoutResource();
+        final int resId = mDialogLayoutRes;
         if (resId == 0) {
             return null;
         }
@@ -157,7 +233,7 @@
         View dialogMessageView = view.findViewById(android.R.id.message);
 
         if (dialogMessageView != null) {
-            final CharSequence message = mPreference.getDialogMessage();
+            final CharSequence message = mDialogMessage;
             int newVisibility = View.GONE;
 
             if (!TextUtils.isEmpty(message)) {
diff --git a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
index 6e7663c..2abafe7 100644
--- a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
@@ -17,13 +17,18 @@
 package android.support.v7.preference;
 
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.view.View;
 import android.widget.EditText;
 
 public class EditTextPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
 
+    private static final String SAVE_STATE_TEXT = "EditTextPreferenceDialogFragment.text";
+
     private EditText mEditText;
 
+    private CharSequence mText;
+
     public static EditTextPreferenceDialogFragmentCompat newInstance(String key) {
         final EditTextPreferenceDialogFragmentCompat
                 fragment = new EditTextPreferenceDialogFragmentCompat();
@@ -34,6 +39,22 @@
     }
 
     @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState == null) {
+            mText = getEditTextPreference().getText();
+        } else {
+            mText = savedInstanceState.getCharSequence(SAVE_STATE_TEXT);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putCharSequence(SAVE_STATE_TEXT, mText);
+    }
+
+    @Override
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
 
@@ -44,7 +65,7 @@
                     " @android:id/edit");
         }
 
-        mEditText.setText(getEditTextPreference().getText());
+        mEditText.setText(mText);
     }
 
     private EditTextPreference getEditTextPreference() {
diff --git a/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java
index 351ed0b..dda461d 100644
--- a/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java
@@ -18,11 +18,21 @@
 
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.v7.app.AlertDialog;
 
+import java.util.ArrayList;
+
 public class ListPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
 
+    private static final String SAVE_STATE_INDEX = "ListPreferenceDialogFragment.index";
+    private static final String SAVE_STATE_ENTRIES = "ListPreferenceDialogFragment.entries";
+    private static final String SAVE_STATE_ENTRY_VALUES =
+            "ListPreferenceDialogFragment.entryValues";
+
     private int mClickedDialogEntryIndex;
+    private CharSequence[] mEntries;
+    private CharSequence[] mEntryValues;
 
     public static ListPreferenceDialogFragmentCompat newInstance(String key) {
         final ListPreferenceDialogFragmentCompat fragment =
@@ -33,6 +43,51 @@
         return fragment;
     }
 
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState == null) {
+            final ListPreference preference = getListPreference();
+
+            if (preference.getEntries() == null || preference.getEntryValues() == null) {
+                throw new IllegalStateException(
+                        "ListPreference requires an entries array and an entryValues array.");
+            }
+
+            mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
+            mEntries = preference.getEntries();
+            mEntryValues = preference.getEntryValues();
+        } else {
+            mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0);
+            mEntries = getCharSequenceArray(savedInstanceState, SAVE_STATE_ENTRIES);
+            mEntryValues = getCharSequenceArray(savedInstanceState, SAVE_STATE_ENTRY_VALUES);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex);
+        putCharSequenceArray(outState, SAVE_STATE_ENTRIES, mEntries);
+        putCharSequenceArray(outState, SAVE_STATE_ENTRY_VALUES, mEntryValues);
+    }
+
+    private static void putCharSequenceArray(Bundle out, String key, CharSequence[] entries) {
+        final ArrayList<String> stored = new ArrayList<>(entries.length);
+
+        for (final CharSequence cs : entries) {
+            stored.add(cs.toString());
+        }
+
+        out.putStringArrayList(key, stored);
+    }
+
+    private static CharSequence[] getCharSequenceArray(Bundle in, String key) {
+        final ArrayList<String> stored = in.getStringArrayList(key);
+
+        return stored == null ? null : stored.toArray(new CharSequence[stored.size()]);
+    }
+
     private ListPreference getListPreference() {
         return (ListPreference) getPreference();
     }
@@ -41,15 +96,7 @@
     protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
         super.onPrepareDialogBuilder(builder);
 
-        final ListPreference preference = getListPreference();
-
-        if (preference.getEntries() == null || preference.getEntryValues() == null) {
-            throw new IllegalStateException(
-                    "ListPreference requires an entries array and an entryValues array.");
-        }
-
-        mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
-        builder.setSingleChoiceItems(preference.getEntries(), mClickedDialogEntryIndex,
+        builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
                 new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int which) {
                         mClickedDialogEntryIndex = which;
@@ -75,9 +122,8 @@
     @Override
     public void onDialogClosed(boolean positiveResult) {
         final ListPreference preference = getListPreference();
-        if (positiveResult && mClickedDialogEntryIndex >= 0 &&
-                preference.getEntryValues() != null) {
-            String value = preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+        if (positiveResult && mClickedDialogEntryIndex >= 0) {
+            String value = mEntryValues[mClickedDialogEntryIndex].toString();
             if (preference.callChangeListener(value)) {
                 preference.setValue(value);
             }
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java
index 6bc2df0..9b6fd5a 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java
@@ -19,7 +19,12 @@
 import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.annotation.LayoutRes;
 import android.support.annotation.NonNull;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
@@ -31,13 +36,35 @@
 import android.view.WindowManager;
 import android.widget.TextView;
 
+/**
+ * Abstract base class which presents a dialog associated with a
+ * {@link android.support.v7.preference.DialogPreference}. Since the preference object may
+ * not be available during fragment re-creation, the necessary information for displaying the dialog
+ * is read once during the initial call to {@link #onCreate(Bundle)} and saved/restored in the saved
+ * instance state. Custom subclasses should also follow this pattern.
+ */
 public abstract class PreferenceDialogFragmentCompat extends DialogFragment implements
         DialogInterface.OnClickListener {
 
     protected static final String ARG_KEY = "key";
 
+    private static final String SAVE_STATE_TITLE = "PreferenceDialogFragment.title";
+    private static final String SAVE_STATE_POSITIVE_TEXT = "PreferenceDialogFragment.positiveText";
+    private static final String SAVE_STATE_NEGATIVE_TEXT = "PreferenceDialogFragment.negativeText";
+    private static final String SAVE_STATE_MESSAGE = "PreferenceDialogFragment.message";
+    private static final String SAVE_STATE_LAYOUT = "PreferenceDialogFragment.layout";
+    private static final String SAVE_STATE_ICON = "PreferenceDialogFragment.icon";
+
     private DialogPreference mPreference;
 
+    private CharSequence mDialogTitle;
+    private CharSequence mPositiveButtonText;
+    private CharSequence mNegativeButtonText;
+    private CharSequence mDialogMessage;
+    private @LayoutRes int mDialogLayoutRes;
+
+    private BitmapDrawable mDialogIcon;
+
     /** Which button was clicked. */
     private int mWhichButtonClicked;
 
@@ -55,26 +82,70 @@
                 (DialogPreference.TargetFragment) rawFragment;
 
         final String key = getArguments().getString(ARG_KEY);
-        mPreference = (DialogPreference) fragment.findPreference(key);
+        if (savedInstanceState == null) {
+            mPreference = (DialogPreference) fragment.findPreference(key);
+            mDialogTitle = mPreference.getDialogTitle();
+            mPositiveButtonText = mPreference.getPositiveButtonText();
+            mNegativeButtonText = mPreference.getNegativeButtonText();
+            mDialogMessage = mPreference.getDialogMessage();
+            mDialogLayoutRes = mPreference.getDialogLayoutResource();
+
+            final Drawable icon = mPreference.getDialogIcon();
+            if (icon == null || icon instanceof BitmapDrawable) {
+                mDialogIcon = (BitmapDrawable) icon;
+            } else {
+                final Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
+                        icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+                final Canvas canvas = new Canvas(bitmap);
+                icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+                icon.draw(canvas);
+                mDialogIcon = new BitmapDrawable(getResources(), bitmap);
+            }
+        } else {
+            mDialogTitle = savedInstanceState.getCharSequence(SAVE_STATE_TITLE);
+            mPositiveButtonText = savedInstanceState.getCharSequence(SAVE_STATE_POSITIVE_TEXT);
+            mNegativeButtonText = savedInstanceState.getCharSequence(SAVE_STATE_NEGATIVE_TEXT);
+            mDialogMessage = savedInstanceState.getCharSequence(SAVE_STATE_MESSAGE);
+            mDialogLayoutRes = savedInstanceState.getInt(SAVE_STATE_LAYOUT, 0);
+            final Bitmap bitmap = savedInstanceState.getParcelable(SAVE_STATE_ICON);
+            if (bitmap != null) {
+                mDialogIcon = new BitmapDrawable(getResources(), bitmap);
+            }
+        }
     }
 
     @Override
-    public @NonNull Dialog onCreateDialog(Bundle savedInstanceState) {
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+
+        outState.putCharSequence(SAVE_STATE_TITLE, mDialogTitle);
+        outState.putCharSequence(SAVE_STATE_POSITIVE_TEXT, mPositiveButtonText);
+        outState.putCharSequence(SAVE_STATE_NEGATIVE_TEXT, mNegativeButtonText);
+        outState.putCharSequence(SAVE_STATE_MESSAGE, mDialogMessage);
+        outState.putInt(SAVE_STATE_LAYOUT, mDialogLayoutRes);
+        if (mDialogIcon != null) {
+            outState.putParcelable(SAVE_STATE_ICON, mDialogIcon.getBitmap());
+        }
+    }
+
+    @Override
+    public @NonNull
+    Dialog onCreateDialog(Bundle savedInstanceState) {
         final Context context = getActivity();
         mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
 
         final AlertDialog.Builder builder = new AlertDialog.Builder(context)
-                .setTitle(mPreference.getDialogTitle())
-                .setIcon(mPreference.getDialogIcon())
-                .setPositiveButton(mPreference.getPositiveButtonText(), this)
-                .setNegativeButton(mPreference.getNegativeButtonText(), this);
+                .setTitle(mDialogTitle)
+                .setIcon(mDialogIcon)
+                .setPositiveButton(mPositiveButtonText, this)
+                .setNegativeButton(mNegativeButtonText, this);
 
         View contentView = onCreateDialogView(context);
         if (contentView != null) {
             onBindDialogView(contentView);
             builder.setView(contentView);
         } else {
-            builder.setMessage(mPreference.getDialogMessage());
+            builder.setMessage(mDialogMessage);
         }
 
         onPrepareDialogBuilder(builder);
@@ -90,12 +161,18 @@
 
     /**
      * Get the preference that requested this dialog. Available after {@link #onCreate(Bundle)} has
-     * been called.
+     * been called on the {@link PreferenceFragmentCompat} which launched this dialog.
      *
      * @return The {@link DialogPreference} associated with this
      * dialog.
      */
     public DialogPreference getPreference() {
+        if (mPreference == null) {
+            final String key = getArguments().getString(ARG_KEY);
+            final DialogPreference.TargetFragment fragment =
+                    (DialogPreference.TargetFragment) getTargetFragment();
+            mPreference = (DialogPreference) fragment.findPreference(key);
+        }
         return mPreference;
     }
 
@@ -135,7 +212,7 @@
      * @see DialogPreference#setLayoutResource(int)
      */
     protected View onCreateDialogView(Context context) {
-        final int resId = mPreference.getDialogLayoutResource();
+        final int resId = mDialogLayoutRes;
         if (resId == 0) {
             return null;
         }
@@ -155,7 +232,7 @@
         View dialogMessageView = view.findViewById(android.R.id.message);
 
         if (dialogMessageView != null) {
-            final CharSequence message = mPreference.getDialogMessage();
+            final CharSequence message = mDialogMessage;
             int newVisibility = View.GONE;
 
             if (!TextUtils.isEmpty(message)) {