diff -r 000000000000 -r 6474c204b198 mobile/android/base/preferences/CustomListPreference.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobile/android/base/preferences/CustomListPreference.java Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,182 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.preferences; + +import org.mozilla.gecko.R; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.preference.Preference; +import android.view.View; +import android.widget.TextView; + +/** + * Represents an element in a CustomListCategory preference menu. + * This preference con display a dialog when clicked, and also supports + * being set as a default item within the preference list category. + */ + +public abstract class CustomListPreference extends Preference implements View.OnLongClickListener { + protected String LOGTAG = "CustomListPreference"; + + // Indices of the buttons of the Dialog. + public static final int INDEX_SET_DEFAULT_BUTTON = 0; + + // Dialog item labels. + private String[] mDialogItems; + + // Dialog displayed when this element is tapped. + protected AlertDialog mDialog; + + // Cache label to avoid repeated use of the resource system. + protected final String LABEL_IS_DEFAULT; + protected final String LABEL_SET_AS_DEFAULT; + protected final String LABEL_REMOVE; + + protected boolean mIsDefault; + + // Enclosing parent category that contains this preference. + protected final CustomListCategory mParentCategory; + + /** + * Create a preference object to represent a list preference that is attached to + * a category. + * + * @param context The activity context we operate under. + * @param parentCategory The PreferenceCategory this object exists within. + */ + public CustomListPreference(Context context, CustomListCategory parentCategory) { + super(context); + + mParentCategory = parentCategory; + setLayoutResource(getPreferenceLayoutResource()); + + setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + CustomListPreference sPref = (CustomListPreference) preference; + sPref.showDialog(); + return true; + } + }); + + Resources res = getContext().getResources(); + + // Fetch these strings now, instead of every time we ever want to relabel a button. + LABEL_IS_DEFAULT = res.getString(R.string.pref_default); + LABEL_SET_AS_DEFAULT = res.getString(R.string.pref_dialog_set_default); + LABEL_REMOVE = res.getString(R.string.pref_dialog_remove); + } + + /** + * Returns the Android resource id for the layout. + */ + protected abstract int getPreferenceLayoutResource(); + + /** + * Set whether this object's UI should display this as the default item. + * Note: This must be called from the UI thread because it touches the view hierarchy. + * + * To ensure proper ordering, this method should only be called after this Preference + * is added to the PreferenceCategory. + * + * @param isDefault Flag indicating if this represents the default list item. + */ + public void setIsDefault(boolean isDefault) { + mIsDefault = isDefault; + if (isDefault) { + setOrder(0); + setSummary(LABEL_IS_DEFAULT); + } else { + setOrder(1); + setSummary(""); + } + } + + private String[] getCachedDialogItems() { + if (mDialogItems == null) { + mDialogItems = createDialogItems(); + } + return mDialogItems; + } + + /** + * Returns the strings to be displayed in the dialog. + */ + abstract protected String[] createDialogItems(); + + /** + * Display a dialog for this preference, when the preference is clicked. + */ + public void showDialog() { + final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle(getTitle().toString()); + builder.setItems(getCachedDialogItems(), new DialogInterface.OnClickListener() { + // Forward relevant events to the container class for handling. + @Override + public void onClick(DialogInterface dialog, int indexClicked) { + hideDialog(); + onDialogIndexClicked(indexClicked); + } + }); + + configureDialogBuilder(builder); + + // We have to construct the dialog itself on the UI thread. + mDialog = builder.create(); + mDialog.setOnShowListener(new DialogInterface.OnShowListener() { + // Called when the dialog is shown (so we're finally able to manipulate button enabledness). + @Override + public void onShow(DialogInterface dialog) { + configureShownDialog(); + } + }); + mDialog.show(); + } + + /** + * (Optional) Configure the AlertDialog builder. + */ + protected void configureDialogBuilder(AlertDialog.Builder builder) { + return; + } + + abstract protected void onDialogIndexClicked(int index); + + /** + * Disables buttons in the shown AlertDialog as required. The button elements are not created + * until after show is called, so this method has to be called from the onShowListener above. + * @see this.showDialog + */ + protected void configureShownDialog() { + // If this is already the default list item, disable the button for setting this as the default. + final TextView defaultButton = (TextView) mDialog.getListView().getChildAt(INDEX_SET_DEFAULT_BUTTON); + if (mIsDefault) { + defaultButton.setEnabled(false); + + // Failure to unregister this listener leads to tapping the button dismissing the dialog + // without doing anything. + defaultButton.setOnClickListener(null); + } + } + + /** + * Hide the dialog we previously created, if any. + */ + public void hideDialog() { + if (mDialog != null && mDialog.isShowing()) { + mDialog.dismiss(); + } + } + + @Override + public boolean onLongClick(View view) { + // Show the preference dialog on long-press. + showDialog(); + return true; + } +}