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