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