Merge "Dismiss Dialog in post instead of immediately"

This commit is contained in:
Treehugger Robot
2018-10-02 21:34:07 +00:00
committed by Gerrit Code Review
2 changed files with 100 additions and 72 deletions

View File

@@ -43,7 +43,7 @@ import android.widget.TextView;
* A base class for {@link Preference} objects that are * A base class for {@link Preference} objects that are
* dialog-based. These preferences will, when clicked, open a dialog showing the * dialog-based. These preferences will, when clicked, open a dialog showing the
* actual preference controls. * actual preference controls.
* *
* @attr ref android.R.styleable#DialogPreference_dialogTitle * @attr ref android.R.styleable#DialogPreference_dialogTitle
* @attr ref android.R.styleable#DialogPreference_dialogMessage * @attr ref android.R.styleable#DialogPreference_dialogMessage
* @attr ref android.R.styleable#DialogPreference_dialogIcon * @attr ref android.R.styleable#DialogPreference_dialogIcon
@@ -56,7 +56,7 @@ public abstract class DialogPreference extends Preference implements
PreferenceManager.OnActivityDestroyListener { PreferenceManager.OnActivityDestroyListener {
@UnsupportedAppUsage @UnsupportedAppUsage
private AlertDialog.Builder mBuilder; private AlertDialog.Builder mBuilder;
@UnsupportedAppUsage @UnsupportedAppUsage
private CharSequence mDialogTitle; private CharSequence mDialogTitle;
@UnsupportedAppUsage @UnsupportedAppUsage
@@ -77,6 +77,14 @@ public abstract class DialogPreference extends Preference implements
@UnsupportedAppUsage @UnsupportedAppUsage
private int mWhichButtonClicked; private int mWhichButtonClicked;
/** Dismiss the dialog on the UI thread, but not inline with handlers */
private final Runnable mDismissRunnable = new Runnable() {
@Override
public void run() {
mDialog.dismiss();
}
};
public DialogPreference( public DialogPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes); super(context, attrs, defStyleAttr, defStyleRes);
@@ -112,7 +120,7 @@ public abstract class DialogPreference extends Preference implements
/** /**
* Sets the title of the dialog. This will be shown on subsequent dialogs. * Sets the title of the dialog. This will be shown on subsequent dialogs.
* *
* @param dialogTitle The title. * @param dialogTitle The title.
*/ */
public void setDialogTitle(CharSequence dialogTitle) { public void setDialogTitle(CharSequence dialogTitle) {
@@ -126,7 +134,7 @@ public abstract class DialogPreference extends Preference implements
public void setDialogTitle(int dialogTitleResId) { public void setDialogTitle(int dialogTitleResId) {
setDialogTitle(getContext().getString(dialogTitleResId)); setDialogTitle(getContext().getString(dialogTitleResId));
} }
/** /**
* Returns the title to be shown on subsequent dialogs. * Returns the title to be shown on subsequent dialogs.
* @return The title. * @return The title.
@@ -134,7 +142,7 @@ public abstract class DialogPreference extends Preference implements
public CharSequence getDialogTitle() { public CharSequence getDialogTitle() {
return mDialogTitle; return mDialogTitle;
} }
/** /**
* Sets the message of the dialog. This will be shown on subsequent dialogs. * Sets the message of the dialog. This will be shown on subsequent dialogs.
* <p> * <p>
@@ -142,7 +150,7 @@ public abstract class DialogPreference extends Preference implements
* list-based dialogs, for example. If setting a custom View on a dialog via * list-based dialogs, for example. If setting a custom View on a dialog via
* {@link #setDialogLayoutResource(int)}, include a text View with ID * {@link #setDialogLayoutResource(int)}, include a text View with ID
* {@link android.R.id#message} and it will be populated with this message. * {@link android.R.id#message} and it will be populated with this message.
* *
* @param dialogMessage The message. * @param dialogMessage The message.
*/ */
public void setDialogMessage(CharSequence dialogMessage) { public void setDialogMessage(CharSequence dialogMessage) {
@@ -156,7 +164,7 @@ public abstract class DialogPreference extends Preference implements
public void setDialogMessage(int dialogMessageResId) { public void setDialogMessage(int dialogMessageResId) {
setDialogMessage(getContext().getString(dialogMessageResId)); setDialogMessage(getContext().getString(dialogMessageResId));
} }
/** /**
* Returns the message to be shown on subsequent dialogs. * Returns the message to be shown on subsequent dialogs.
* @return The message. * @return The message.
@@ -164,26 +172,26 @@ public abstract class DialogPreference extends Preference implements
public CharSequence getDialogMessage() { public CharSequence getDialogMessage() {
return mDialogMessage; return mDialogMessage;
} }
/** /**
* Sets the icon of the dialog. This will be shown on subsequent dialogs. * Sets the icon of the dialog. This will be shown on subsequent dialogs.
* *
* @param dialogIcon The icon, as a {@link Drawable}. * @param dialogIcon The icon, as a {@link Drawable}.
*/ */
public void setDialogIcon(Drawable dialogIcon) { public void setDialogIcon(Drawable dialogIcon) {
mDialogIcon = dialogIcon; mDialogIcon = dialogIcon;
} }
/** /**
* Sets the icon (resource ID) of the dialog. This will be shown on * Sets the icon (resource ID) of the dialog. This will be shown on
* subsequent dialogs. * subsequent dialogs.
* *
* @param dialogIconRes The icon, as a resource ID. * @param dialogIconRes The icon, as a resource ID.
*/ */
public void setDialogIcon(@DrawableRes int dialogIconRes) { public void setDialogIcon(@DrawableRes int dialogIconRes) {
mDialogIcon = getContext().getDrawable(dialogIconRes); mDialogIcon = getContext().getDrawable(dialogIconRes);
} }
/** /**
* Returns the icon to be shown on subsequent dialogs. * Returns the icon to be shown on subsequent dialogs.
* @return The icon, as a {@link Drawable}. * @return The icon, as a {@link Drawable}.
@@ -191,11 +199,11 @@ public abstract class DialogPreference extends Preference implements
public Drawable getDialogIcon() { public Drawable getDialogIcon() {
return mDialogIcon; return mDialogIcon;
} }
/** /**
* Sets the text of the positive button of the dialog. This will be shown on * Sets the text of the positive button of the dialog. This will be shown on
* subsequent dialogs. * subsequent dialogs.
* *
* @param positiveButtonText The text of the positive button. * @param positiveButtonText The text of the positive button.
*/ */
public void setPositiveButtonText(CharSequence positiveButtonText) { public void setPositiveButtonText(CharSequence positiveButtonText) {
@@ -209,27 +217,27 @@ public abstract class DialogPreference extends Preference implements
public void setPositiveButtonText(@StringRes int positiveButtonTextResId) { public void setPositiveButtonText(@StringRes int positiveButtonTextResId) {
setPositiveButtonText(getContext().getString(positiveButtonTextResId)); setPositiveButtonText(getContext().getString(positiveButtonTextResId));
} }
/** /**
* Returns the text of the positive button to be shown on subsequent * Returns the text of the positive button to be shown on subsequent
* dialogs. * dialogs.
* *
* @return The text of the positive button. * @return The text of the positive button.
*/ */
public CharSequence getPositiveButtonText() { public CharSequence getPositiveButtonText() {
return mPositiveButtonText; return mPositiveButtonText;
} }
/** /**
* Sets the text of the negative button of the dialog. This will be shown on * Sets the text of the negative button of the dialog. This will be shown on
* subsequent dialogs. * subsequent dialogs.
* *
* @param negativeButtonText The text of the negative button. * @param negativeButtonText The text of the negative button.
*/ */
public void setNegativeButtonText(CharSequence negativeButtonText) { public void setNegativeButtonText(CharSequence negativeButtonText) {
mNegativeButtonText = negativeButtonText; mNegativeButtonText = negativeButtonText;
} }
/** /**
* @see #setNegativeButtonText(CharSequence) * @see #setNegativeButtonText(CharSequence)
* @param negativeButtonTextResId The negative button text as a resource. * @param negativeButtonTextResId The negative button text as a resource.
@@ -237,38 +245,38 @@ public abstract class DialogPreference extends Preference implements
public void setNegativeButtonText(@StringRes int negativeButtonTextResId) { public void setNegativeButtonText(@StringRes int negativeButtonTextResId) {
setNegativeButtonText(getContext().getString(negativeButtonTextResId)); setNegativeButtonText(getContext().getString(negativeButtonTextResId));
} }
/** /**
* Returns the text of the negative button to be shown on subsequent * Returns the text of the negative button to be shown on subsequent
* dialogs. * dialogs.
* *
* @return The text of the negative button. * @return The text of the negative button.
*/ */
public CharSequence getNegativeButtonText() { public CharSequence getNegativeButtonText() {
return mNegativeButtonText; return mNegativeButtonText;
} }
/** /**
* Sets the layout resource that is inflated as the {@link View} to be shown * Sets the layout resource that is inflated as the {@link View} to be shown
* as the content View of subsequent dialogs. * as the content View of subsequent dialogs.
* *
* @param dialogLayoutResId The layout resource ID to be inflated. * @param dialogLayoutResId The layout resource ID to be inflated.
* @see #setDialogMessage(CharSequence) * @see #setDialogMessage(CharSequence)
*/ */
public void setDialogLayoutResource(int dialogLayoutResId) { public void setDialogLayoutResource(int dialogLayoutResId) {
mDialogLayoutResId = dialogLayoutResId; mDialogLayoutResId = dialogLayoutResId;
} }
/** /**
* Returns the layout resource that is used as the content View for * Returns the layout resource that is used as the content View for
* subsequent dialogs. * subsequent dialogs.
* *
* @return The layout resource. * @return The layout resource.
*/ */
public int getDialogLayoutResource() { public int getDialogLayoutResource() {
return mDialogLayoutResId; return mDialogLayoutResId;
} }
/** /**
* Prepares the dialog builder to be shown when the preference is clicked. * Prepares the dialog builder to be shown when the preference is clicked.
* Use this to set custom properties on the dialog. * Use this to set custom properties on the dialog.
@@ -278,7 +286,7 @@ public abstract class DialogPreference extends Preference implements
*/ */
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
} }
@Override @Override
protected void onClick() { protected void onClick() {
if (mDialog != null && mDialog.isShowing()) return; if (mDialog != null && mDialog.isShowing()) return;
@@ -290,14 +298,14 @@ public abstract class DialogPreference extends Preference implements
* Shows the dialog associated with this Preference. This is normally initiated * Shows the dialog associated with this Preference. This is normally initiated
* automatically on clicking on the preference. Call this method if you need to * automatically on clicking on the preference. Call this method if you need to
* show the dialog on some other event. * show the dialog on some other event.
* *
* @param state Optional instance state to restore on the dialog * @param state Optional instance state to restore on the dialog
*/ */
protected void showDialog(Bundle state) { protected void showDialog(Bundle state) {
Context context = getContext(); Context context = getContext();
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE; mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
mBuilder = new AlertDialog.Builder(context) mBuilder = new AlertDialog.Builder(context)
.setTitle(mDialogTitle) .setTitle(mDialogTitle)
.setIcon(mDialogIcon) .setIcon(mDialogIcon)
@@ -311,11 +319,11 @@ public abstract class DialogPreference extends Preference implements
} else { } else {
mBuilder.setMessage(mDialogMessage); mBuilder.setMessage(mDialogMessage);
} }
onPrepareDialogBuilder(mBuilder); onPrepareDialogBuilder(mBuilder);
getPreferenceManager().registerOnActivityDestroyListener(this); getPreferenceManager().registerOnActivityDestroyListener(this);
// Create the dialog // Create the dialog
final Dialog dialog = mDialog = mBuilder.create(); final Dialog dialog = mDialog = mBuilder.create();
if (state != null) { if (state != null) {
@@ -324,10 +332,29 @@ public abstract class DialogPreference extends Preference implements
if (needInputMethod()) { if (needInputMethod()) {
requestInputMethod(dialog); requestInputMethod(dialog);
} }
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
removeDismissCallbacks();
}
});
dialog.setOnDismissListener(this); dialog.setOnDismissListener(this);
dialog.show(); dialog.show();
} }
void postDismiss() {
removeDismissCallbacks();
View decorView = mDialog.getWindow().getDecorView();
decorView.post(mDismissRunnable);
}
private void removeDismissCallbacks() {
if (mDialog != null && mDialog.getWindow() != null
&& mDialog.getWindow().getDecorView() != null) {
mDialog.getWindow().getDecorView().removeCallbacks(mDismissRunnable);
}
}
/** /**
* Returns whether the preference needs to display a soft input method when the dialog * Returns whether the preference needs to display a soft input method when the dialog
* is displayed. Default is false. Subclasses should override this method if they need * is displayed. Default is false. Subclasses should override this method if they need
@@ -350,7 +377,7 @@ public abstract class DialogPreference extends Preference implements
* Creates the content view for the dialog (if a custom content view is * Creates the content view for the dialog (if a custom content view is
* required). By default, it inflates the dialog layout resource if it is * required). By default, it inflates the dialog layout resource if it is
* set. * set.
* *
* @return The content View for the dialog. * @return The content View for the dialog.
* @see #setLayoutResource(int) * @see #setLayoutResource(int)
*/ */
@@ -358,48 +385,49 @@ public abstract class DialogPreference extends Preference implements
if (mDialogLayoutResId == 0) { if (mDialogLayoutResId == 0) {
return null; return null;
} }
LayoutInflater inflater = LayoutInflater.from(mBuilder.getContext()); LayoutInflater inflater = LayoutInflater.from(mBuilder.getContext());
return inflater.inflate(mDialogLayoutResId, null); return inflater.inflate(mDialogLayoutResId, null);
} }
/** /**
* Binds views in the content View of the dialog to data. * Binds views in the content View of the dialog to data.
* <p> * <p>
* Make sure to call through to the superclass implementation. * Make sure to call through to the superclass implementation.
* *
* @param view The content View of the dialog, if it is custom. * @param view The content View of the dialog, if it is custom.
*/ */
@CallSuper @CallSuper
protected void onBindDialogView(View view) { protected void onBindDialogView(View view) {
View dialogMessageView = view.findViewById(com.android.internal.R.id.message); View dialogMessageView = view.findViewById(com.android.internal.R.id.message);
if (dialogMessageView != null) { if (dialogMessageView != null) {
final CharSequence message = getDialogMessage(); final CharSequence message = getDialogMessage();
int newVisibility = View.GONE; int newVisibility = View.GONE;
if (!TextUtils.isEmpty(message)) { if (!TextUtils.isEmpty(message)) {
if (dialogMessageView instanceof TextView) { if (dialogMessageView instanceof TextView) {
((TextView) dialogMessageView).setText(message); ((TextView) dialogMessageView).setText(message);
} }
newVisibility = View.VISIBLE; newVisibility = View.VISIBLE;
} }
if (dialogMessageView.getVisibility() != newVisibility) { if (dialogMessageView.getVisibility() != newVisibility) {
dialogMessageView.setVisibility(newVisibility); dialogMessageView.setVisibility(newVisibility);
} }
} }
} }
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
mWhichButtonClicked = which; mWhichButtonClicked = which;
} }
@Override
public void onDismiss(DialogInterface dialog) { public void onDismiss(DialogInterface dialog) {
removeDismissCallbacks();
getPreferenceManager().unregisterOnActivityDestroyListener(this); getPreferenceManager().unregisterOnActivityDestroyListener(this);
mDialog = null; mDialog = null;
onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE); onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
} }
@@ -407,7 +435,7 @@ public abstract class DialogPreference extends Preference implements
/** /**
* Called when the dialog is dismissed and should be used to save data to * Called when the dialog is dismissed and should be used to save data to
* the {@link SharedPreferences}. * the {@link SharedPreferences}.
* *
* @param positiveResult Whether the positive button was clicked (true), or * @param positiveResult Whether the positive button was clicked (true), or
* the negative button was clicked or the dialog was canceled (false). * the negative button was clicked or the dialog was canceled (false).
*/ */
@@ -416,7 +444,7 @@ public abstract class DialogPreference extends Preference implements
/** /**
* Gets the dialog that is shown by this preference. * Gets the dialog that is shown by this preference.
* *
* @return The dialog, or null if a dialog is not being shown. * @return The dialog, or null if a dialog is not being shown.
*/ */
public Dialog getDialog() { public Dialog getDialog() {
@@ -427,11 +455,11 @@ public abstract class DialogPreference extends Preference implements
* {@inheritDoc} * {@inheritDoc}
*/ */
public void onActivityDestroy() { public void onActivityDestroy() {
if (mDialog == null || !mDialog.isShowing()) { if (mDialog == null || !mDialog.isShowing()) {
return; return;
} }
mDialog.dismiss(); mDialog.dismiss();
} }
@@ -466,7 +494,7 @@ public abstract class DialogPreference extends Preference implements
private static class SavedState extends BaseSavedState { private static class SavedState extends BaseSavedState {
boolean isDialogShowing; boolean isDialogShowing;
Bundle dialogBundle; Bundle dialogBundle;
public SavedState(Parcel source) { public SavedState(Parcel source) {
super(source); super(source);
isDialogShowing = source.readInt() == 1; isDialogShowing = source.readInt() == 1;
@@ -495,5 +523,5 @@ public abstract class DialogPreference extends Preference implements
} }
}; };
} }
} }

View File

@@ -33,7 +33,7 @@ import android.util.AttributeSet;
* <p> * <p>
* This preference will store a string into the SharedPreferences. This string will be the value * This preference will store a string into the SharedPreferences. This string will be the value
* from the {@link #setEntryValues(CharSequence[])} array. * from the {@link #setEntryValues(CharSequence[])} array.
* *
* @attr ref android.R.styleable#ListPreference_entries * @attr ref android.R.styleable#ListPreference_entries
* @attr ref android.R.styleable#ListPreference_entryValues * @attr ref android.R.styleable#ListPreference_entryValues
*/ */
@@ -193,7 +193,7 @@ public class ListPreference extends DialogPreference {
/** /**
* Sets the value to the given index from the entry values. * Sets the value to the given index from the entry values.
* *
* @param index The index of the value to set. * @param index The index of the value to set.
*/ */
public void setValueIndex(int index) { public void setValueIndex(int index) {
@@ -201,30 +201,30 @@ public class ListPreference extends DialogPreference {
setValue(mEntryValues[index].toString()); setValue(mEntryValues[index].toString());
} }
} }
/** /**
* Returns the value of the key. This should be one of the entries in * Returns the value of the key. This should be one of the entries in
* {@link #getEntryValues()}. * {@link #getEntryValues()}.
* *
* @return The value of the key. * @return The value of the key.
*/ */
public String getValue() { public String getValue() {
return mValue; return mValue;
} }
/** /**
* Returns the entry corresponding to the current value. * Returns the entry corresponding to the current value.
* *
* @return The entry corresponding to the current value, or null. * @return The entry corresponding to the current value, or null.
*/ */
public CharSequence getEntry() { public CharSequence getEntry() {
int index = getValueIndex(); int index = getValueIndex();
return index >= 0 && mEntries != null ? mEntries[index] : null; return index >= 0 && mEntries != null ? mEntries[index] : null;
} }
/** /**
* Returns the index of the given value (in the entry values array). * Returns the index of the given value (in the entry values array).
* *
* @param value The value whose index should be returned. * @param value The value whose index should be returned.
* @return The index of the value, or -1 if not found. * @return The index of the value, or -1 if not found.
*/ */
@@ -238,22 +238,22 @@ public class ListPreference extends DialogPreference {
} }
return -1; return -1;
} }
private int getValueIndex() { private int getValueIndex() {
return findIndexOfValue(mValue); return findIndexOfValue(mValue);
} }
@Override @Override
protected void onPrepareDialogBuilder(Builder builder) { protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder); super.onPrepareDialogBuilder(builder);
if (mEntries == null || mEntryValues == null) { if (mEntries == null || mEntryValues == null) {
throw new IllegalStateException( throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array."); "ListPreference requires an entries array and an entryValues array.");
} }
mClickedDialogEntryIndex = getValueIndex(); mClickedDialogEntryIndex = getValueIndex();
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex, builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which; mClickedDialogEntryIndex = which;
@@ -263,10 +263,10 @@ public class ListPreference extends DialogPreference {
* click, and dismisses the dialog. * click, and dismisses the dialog.
*/ */
ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE); ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
dialog.dismiss(); postDismiss();
} }
}); });
/* /*
* The typical interaction for list-based dialogs is to have * The typical interaction for list-based dialogs is to have
* click-on-an-item dismiss the dialog instead of the user having to * click-on-an-item dismiss the dialog instead of the user having to
@@ -278,7 +278,7 @@ public class ListPreference extends DialogPreference {
@Override @Override
protected void onDialogClosed(boolean positiveResult) { protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult); super.onDialogClosed(positiveResult);
if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) { if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
String value = mEntryValues[mClickedDialogEntryIndex].toString(); String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (callChangeListener(value)) { if (callChangeListener(value)) {
@@ -296,7 +296,7 @@ public class ListPreference extends DialogPreference {
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue); setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
} }
@Override @Override
protected Parcelable onSaveInstanceState() { protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState(); final Parcelable superState = super.onSaveInstanceState();
@@ -304,7 +304,7 @@ public class ListPreference extends DialogPreference {
// No need to save instance state since it's persistent // No need to save instance state since it's persistent
return superState; return superState;
} }
final SavedState myState = new SavedState(superState); final SavedState myState = new SavedState(superState);
myState.value = getValue(); myState.value = getValue();
return myState; return myState;
@@ -317,15 +317,15 @@ public class ListPreference extends DialogPreference {
super.onRestoreInstanceState(state); super.onRestoreInstanceState(state);
return; return;
} }
SavedState myState = (SavedState) state; SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState()); super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value); setValue(myState.value);
} }
private static class SavedState extends BaseSavedState { private static class SavedState extends BaseSavedState {
String value; String value;
public SavedState(Parcel source) { public SavedState(Parcel source) {
super(source); super(source);
value = source.readString(); value = source.readString();
@@ -352,5 +352,5 @@ public class ListPreference extends DialogPreference {
} }
}; };
} }
} }