1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/preferences/CustomListPreference.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,182 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.preferences; 1.9 + 1.10 +import org.mozilla.gecko.R; 1.11 + 1.12 +import android.app.AlertDialog; 1.13 +import android.content.Context; 1.14 +import android.content.DialogInterface; 1.15 +import android.content.res.Resources; 1.16 +import android.preference.Preference; 1.17 +import android.view.View; 1.18 +import android.widget.TextView; 1.19 + 1.20 +/** 1.21 + * Represents an element in a <code>CustomListCategory</code> preference menu. 1.22 + * This preference con display a dialog when clicked, and also supports 1.23 + * being set as a default item within the preference list category. 1.24 + */ 1.25 + 1.26 +public abstract class CustomListPreference extends Preference implements View.OnLongClickListener { 1.27 + protected String LOGTAG = "CustomListPreference"; 1.28 + 1.29 + // Indices of the buttons of the Dialog. 1.30 + public static final int INDEX_SET_DEFAULT_BUTTON = 0; 1.31 + 1.32 + // Dialog item labels. 1.33 + private String[] mDialogItems; 1.34 + 1.35 + // Dialog displayed when this element is tapped. 1.36 + protected AlertDialog mDialog; 1.37 + 1.38 + // Cache label to avoid repeated use of the resource system. 1.39 + protected final String LABEL_IS_DEFAULT; 1.40 + protected final String LABEL_SET_AS_DEFAULT; 1.41 + protected final String LABEL_REMOVE; 1.42 + 1.43 + protected boolean mIsDefault; 1.44 + 1.45 + // Enclosing parent category that contains this preference. 1.46 + protected final CustomListCategory mParentCategory; 1.47 + 1.48 + /** 1.49 + * Create a preference object to represent a list preference that is attached to 1.50 + * a category. 1.51 + * 1.52 + * @param context The activity context we operate under. 1.53 + * @param parentCategory The PreferenceCategory this object exists within. 1.54 + */ 1.55 + public CustomListPreference(Context context, CustomListCategory parentCategory) { 1.56 + super(context); 1.57 + 1.58 + mParentCategory = parentCategory; 1.59 + setLayoutResource(getPreferenceLayoutResource()); 1.60 + 1.61 + setOnPreferenceClickListener(new OnPreferenceClickListener() { 1.62 + @Override 1.63 + public boolean onPreferenceClick(Preference preference) { 1.64 + CustomListPreference sPref = (CustomListPreference) preference; 1.65 + sPref.showDialog(); 1.66 + return true; 1.67 + } 1.68 + }); 1.69 + 1.70 + Resources res = getContext().getResources(); 1.71 + 1.72 + // Fetch these strings now, instead of every time we ever want to relabel a button. 1.73 + LABEL_IS_DEFAULT = res.getString(R.string.pref_default); 1.74 + LABEL_SET_AS_DEFAULT = res.getString(R.string.pref_dialog_set_default); 1.75 + LABEL_REMOVE = res.getString(R.string.pref_dialog_remove); 1.76 + } 1.77 + 1.78 + /** 1.79 + * Returns the Android resource id for the layout. 1.80 + */ 1.81 + protected abstract int getPreferenceLayoutResource(); 1.82 + 1.83 + /** 1.84 + * Set whether this object's UI should display this as the default item. 1.85 + * Note: This must be called from the UI thread because it touches the view hierarchy. 1.86 + * 1.87 + * To ensure proper ordering, this method should only be called after this Preference 1.88 + * is added to the PreferenceCategory. 1.89 + * 1.90 + * @param isDefault Flag indicating if this represents the default list item. 1.91 + */ 1.92 + public void setIsDefault(boolean isDefault) { 1.93 + mIsDefault = isDefault; 1.94 + if (isDefault) { 1.95 + setOrder(0); 1.96 + setSummary(LABEL_IS_DEFAULT); 1.97 + } else { 1.98 + setOrder(1); 1.99 + setSummary(""); 1.100 + } 1.101 + } 1.102 + 1.103 + private String[] getCachedDialogItems() { 1.104 + if (mDialogItems == null) { 1.105 + mDialogItems = createDialogItems(); 1.106 + } 1.107 + return mDialogItems; 1.108 + } 1.109 + 1.110 + /** 1.111 + * Returns the strings to be displayed in the dialog. 1.112 + */ 1.113 + abstract protected String[] createDialogItems(); 1.114 + 1.115 + /** 1.116 + * Display a dialog for this preference, when the preference is clicked. 1.117 + */ 1.118 + public void showDialog() { 1.119 + final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 1.120 + builder.setTitle(getTitle().toString()); 1.121 + builder.setItems(getCachedDialogItems(), new DialogInterface.OnClickListener() { 1.122 + // Forward relevant events to the container class for handling. 1.123 + @Override 1.124 + public void onClick(DialogInterface dialog, int indexClicked) { 1.125 + hideDialog(); 1.126 + onDialogIndexClicked(indexClicked); 1.127 + } 1.128 + }); 1.129 + 1.130 + configureDialogBuilder(builder); 1.131 + 1.132 + // We have to construct the dialog itself on the UI thread. 1.133 + mDialog = builder.create(); 1.134 + mDialog.setOnShowListener(new DialogInterface.OnShowListener() { 1.135 + // Called when the dialog is shown (so we're finally able to manipulate button enabledness). 1.136 + @Override 1.137 + public void onShow(DialogInterface dialog) { 1.138 + configureShownDialog(); 1.139 + } 1.140 + }); 1.141 + mDialog.show(); 1.142 + } 1.143 + 1.144 + /** 1.145 + * (Optional) Configure the AlertDialog builder. 1.146 + */ 1.147 + protected void configureDialogBuilder(AlertDialog.Builder builder) { 1.148 + return; 1.149 + } 1.150 + 1.151 + abstract protected void onDialogIndexClicked(int index); 1.152 + 1.153 + /** 1.154 + * Disables buttons in the shown AlertDialog as required. The button elements are not created 1.155 + * until after show is called, so this method has to be called from the onShowListener above. 1.156 + * @see this.showDialog 1.157 + */ 1.158 + protected void configureShownDialog() { 1.159 + // If this is already the default list item, disable the button for setting this as the default. 1.160 + final TextView defaultButton = (TextView) mDialog.getListView().getChildAt(INDEX_SET_DEFAULT_BUTTON); 1.161 + if (mIsDefault) { 1.162 + defaultButton.setEnabled(false); 1.163 + 1.164 + // Failure to unregister this listener leads to tapping the button dismissing the dialog 1.165 + // without doing anything. 1.166 + defaultButton.setOnClickListener(null); 1.167 + } 1.168 + } 1.169 + 1.170 + /** 1.171 + * Hide the dialog we previously created, if any. 1.172 + */ 1.173 + public void hideDialog() { 1.174 + if (mDialog != null && mDialog.isShowing()) { 1.175 + mDialog.dismiss(); 1.176 + } 1.177 + } 1.178 + 1.179 + @Override 1.180 + public boolean onLongClick(View view) { 1.181 + // Show the preference dialog on long-press. 1.182 + showDialog(); 1.183 + return true; 1.184 + } 1.185 +}