1 package ${packageName}; 2 3 import android.annotation.TargetApi; 4 import android.content.Context; 5 import android.content.res.Configuration; 6 import android.media.Ringtone; 7 import android.media.RingtoneManager; 8 import android.net.Uri; 9 import android.os.Build; 10 import android.os.Bundle; 11 import android.preference.ListPreference; 12 import android.preference.Preference; 13 import android.preference.PreferenceActivity; 14 import android.preference.PreferenceCategory; 15 import android.preference.PreferenceFragment; 16 import android.preference.PreferenceManager; 17 import android.preference.RingtonePreference; 18 import android.text.TextUtils; 19 <#if parentActivityClass != ""> 20 import android.view.MenuItem; 21 import android.support.v4.app.NavUtils; 22 </#if> 23 24 import java.util.List; 25 26 /** 27 * A {@link PreferenceActivity} that presents a set of application settings. On 28 * handset devices, settings are presented as a single list. On tablets, 29 * settings are split by category, with category headers shown to the left of 30 * the list of settings. 31 * <p> 32 * See <a href="http://developer.android.com/design/patterns/settings.html"> 33 * Android Design: Settings</a> for design guidelines and the <a 34 * href="http://developer.android.com/guide/topics/ui/settings.html">Settings 35 * API Guide</a> for more information on developing a Settings UI. 36 */ 37 public class ${activityClass} extends PreferenceActivity { 38 /** 39 * Determines whether to always show the simplified settings UI, where 40 * settings are presented in a single list. When false, settings are shown 41 * as a master/detail two-pane view on tablets. When true, a single pane is 42 * shown on tablets. 43 */ 44 private static final boolean ALWAYS_SIMPLE_PREFS = false; 45 46 <#if parentActivityClass != ""> 47 @Override 48 protected void onCreate(Bundle savedInstanceState) { 49 super.onCreate(savedInstanceState); 50 setupActionBar(); 51 } 52 53 /** 54 * Set up the {@link android.app.ActionBar}, if the API is available. 55 */ 56 @TargetApi(Build.VERSION_CODES.HONEYCOMB) 57 private void setupActionBar() { 58 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 59 // Show the Up button in the action bar. 60 getActionBar().setDisplayHomeAsUpEnabled(true); 61 } 62 } 63 64 @Override 65 public boolean onOptionsItemSelected(MenuItem item) { 66 switch (item.getItemId()) { 67 case android.R.id.home: 68 // This ID represents the Home or Up button. In the case of this 69 // activity, the Up button is shown. Use NavUtils to allow users 70 // to navigate up one level in the application structure. For 71 // more details, see the Navigation pattern on Android Design: 72 // 73 // http://developer.android.com/design/patterns/navigation.html#up-vs-back 74 // 75 // TODO: If Settings has multiple levels, Up should navigate up 76 // that hierarchy. 77 NavUtils.navigateUpFromSameTask(this); 78 return true; 79 } 80 return super.onOptionsItemSelected(item); 81 } 82 </#if> 83 84 @Override 85 protected void onPostCreate(Bundle savedInstanceState) { 86 super.onPostCreate(savedInstanceState); 87 88 setupSimplePreferencesScreen(); 89 } 90 91 /** 92 * Shows the simplified settings UI if the device configuration if the 93 * device configuration dictates that a simplified, single-pane UI should be 94 * shown. 95 */ 96 private void setupSimplePreferencesScreen() { 97 if (!isSimplePreferences(this)) { 98 return; 99 } 100 101 // In the simplified UI, fragments are not used at all and we instead 102 // use the older PreferenceActivity APIs. 103 104 // Add 'general' preferences. 105 addPreferencesFromResource(R.xml.pref_general); 106 107 // Add 'notifications' preferences, and a corresponding header. 108 PreferenceCategory fakeHeader = new PreferenceCategory(this); 109 fakeHeader.setTitle(R.string.pref_header_notifications); 110 getPreferenceScreen().addPreference(fakeHeader); 111 addPreferencesFromResource(R.xml.pref_notification); 112 113 // Add 'data and sync' preferences, and a corresponding header. 114 fakeHeader = new PreferenceCategory(this); 115 fakeHeader.setTitle(R.string.pref_header_data_sync); 116 getPreferenceScreen().addPreference(fakeHeader); 117 addPreferencesFromResource(R.xml.pref_data_sync); 118 119 // Bind the summaries of EditText/List/Dialog/Ringtone preferences to 120 // their values. When their values change, their summaries are updated 121 // to reflect the new value, per the Android Design guidelines. 122 bindPreferenceSummaryToValue(findPreference("example_text")); 123 bindPreferenceSummaryToValue(findPreference("example_list")); 124 bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone")); 125 bindPreferenceSummaryToValue(findPreference("sync_frequency")); 126 } 127 128 /** {@inheritDoc} */ 129 @Override 130 public boolean onIsMultiPane() { 131 return isXLargeTablet(this) && !isSimplePreferences(this); 132 } 133 134 /** 135 * Helper method to determine if the device has an extra-large screen. For 136 * example, 10" tablets are extra-large. 137 */ 138 private static boolean isXLargeTablet(Context context) { 139 return (context.getResources().getConfiguration().screenLayout 140 & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; 141 } 142 143 /** 144 * Determines whether the simplified settings UI should be shown. This is 145 * true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device 146 * doesn't have newer APIs like {@link PreferenceFragment}, or the device 147 * doesn't have an extra-large screen. In these cases, a single-pane 148 * "simplified" settings UI should be shown. 149 */ 150 private static boolean isSimplePreferences(Context context) { 151 return ALWAYS_SIMPLE_PREFS 152 || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB 153 || !isXLargeTablet(context); 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 @TargetApi(Build.VERSION_CODES.HONEYCOMB) 159 public void onBuildHeaders(List<Header> target) { 160 if (!isSimplePreferences(this)) { 161 loadHeadersFromResource(R.xml.pref_headers, target); 162 } 163 } 164 165 /** 166 * A preference value change listener that updates the preference's summary 167 * to reflect its new value. 168 */ 169 private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { 170 @Override 171 public boolean onPreferenceChange(Preference preference, Object value) { 172 String stringValue = value.toString(); 173 174 if (preference instanceof ListPreference) { 175 // For list preferences, look up the correct display value in 176 // the preference's 'entries' list. 177 ListPreference listPreference = (ListPreference) preference; 178 int index = listPreference.findIndexOfValue(stringValue); 179 180 // Set the summary to reflect the new value. 181 preference.setSummary( 182 index >= 0 183 ? listPreference.getEntries()[index] 184 : null); 185 186 } else if (preference instanceof RingtonePreference) { 187 // For ringtone preferences, look up the correct display value 188 // using RingtoneManager. 189 if (TextUtils.isEmpty(stringValue)) { 190 // Empty values correspond to 'silent' (no ringtone). 191 preference.setSummary(R.string.pref_ringtone_silent); 192 193 } else { 194 Ringtone ringtone = RingtoneManager.getRingtone( 195 preference.getContext(), Uri.parse(stringValue)); 196 197 if (ringtone == null) { 198 // Clear the summary if there was a lookup error. 199 preference.setSummary(null); 200 } else { 201 // Set the summary to reflect the new ringtone display 202 // name. 203 String name = ringtone.getTitle(preference.getContext()); 204 preference.setSummary(name); 205 } 206 } 207 208 } else { 209 // For all other preferences, set the summary to the value's 210 // simple string representation. 211 preference.setSummary(stringValue); 212 } 213 return true; 214 } 215 }; 216 217 /** 218 * Binds a preference's summary to its value. More specifically, when the 219 * preference's value is changed, its summary (line of text below the 220 * preference title) is updated to reflect the value. The summary is also 221 * immediately updated upon calling this method. The exact display format is 222 * dependent on the type of preference. 223 * 224 * @see #sBindPreferenceSummaryToValueListener 225 */ 226 private static void bindPreferenceSummaryToValue(Preference preference) { 227 // Set the listener to watch for value changes. 228 preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); 229 230 // Trigger the listener immediately with the preference's 231 // current value. 232 sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, 233 PreferenceManager 234 .getDefaultSharedPreferences(preference.getContext()) 235 .getString(preference.getKey(), "")); 236 } 237 238 /** 239 * This fragment shows general preferences only. It is used when the 240 * activity is showing a two-pane settings UI. 241 */ 242 @TargetApi(Build.VERSION_CODES.HONEYCOMB) 243 public static class GeneralPreferenceFragment extends PreferenceFragment { 244 @Override 245 public void onCreate(Bundle savedInstanceState) { 246 super.onCreate(savedInstanceState); 247 addPreferencesFromResource(R.xml.pref_general); 248 249 // Bind the summaries of EditText/List/Dialog/Ringtone preferences 250 // to their values. When their values change, their summaries are 251 // updated to reflect the new value, per the Android Design 252 // guidelines. 253 bindPreferenceSummaryToValue(findPreference("example_text")); 254 bindPreferenceSummaryToValue(findPreference("example_list")); 255 } 256 } 257 258 /** 259 * This fragment shows notification preferences only. It is used when the 260 * activity is showing a two-pane settings UI. 261 */ 262 @TargetApi(Build.VERSION_CODES.HONEYCOMB) 263 public static class NotificationPreferenceFragment extends PreferenceFragment { 264 @Override 265 public void onCreate(Bundle savedInstanceState) { 266 super.onCreate(savedInstanceState); 267 addPreferencesFromResource(R.xml.pref_notification); 268 269 // Bind the summaries of EditText/List/Dialog/Ringtone preferences 270 // to their values. When their values change, their summaries are 271 // updated to reflect the new value, per the Android Design 272 // guidelines. 273 bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone")); 274 } 275 } 276 277 /** 278 * This fragment shows data and sync preferences only. It is used when the 279 * activity is showing a two-pane settings UI. 280 */ 281 @TargetApi(Build.VERSION_CODES.HONEYCOMB) 282 public static class DataSyncPreferenceFragment extends PreferenceFragment { 283 @Override 284 public void onCreate(Bundle savedInstanceState) { 285 super.onCreate(savedInstanceState); 286 addPreferencesFromResource(R.xml.pref_data_sync); 287 288 // Bind the summaries of EditText/List/Dialog/Ringtone preferences 289 // to their values. When their values change, their summaries are 290 // updated to reflect the new value, per the Android Design 291 // guidelines. 292 bindPreferenceSummaryToValue(findPreference("sync_frequency")); 293 } 294 } 295 } 296