Java tutorial
//////////////////////////////////////////////////////////////////////////////// // Danbooru Gallery Android - an danbooru-style imageboard browser // Copyright (C) 2014 Victor Tseng // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/> //////////////////////////////////////////////////////////////////////////////// package tw.idv.palatis.danboorugallery; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.view.MenuItem; import java.io.File; import java.util.List; import tw.idv.palatis.danboorugallery.database.PostsTable; import tw.idv.palatis.danboorugallery.picasso.Picasso; /** * A {@link PreferenceActivity} that presents a set of application settings. On * handset devices, settings are presented as a single list. On tablets, * settings are split by category, with category headers shown to the left of * the list of settings. * <p> * See <a href="http://developer.android.com/design/patterns/settings.html"> * Android Design: Settings</a> for design guidelines and the <a * href="http://developer.android.com/guide/topics/ui/settings.html">Settings * API Guide</a> for more information on developing a Settings UI. */ public class SettingsActivity extends PreferenceActivity { private static final String TAG = "SettingsActivity"; @Override protected boolean isValidFragment(String fragmentName) { return true; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActionBar().setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { // This ID represents the Home or Up button. In the case of this // activity, the Up button is shown. Use NavUtils to allow users // to navigate up one level in the application structure. For // more details, see the Navigation pattern on Android Design: // // http://developer.android.com/design/patterns/navigation.html#up-vs-back // // TODO: If Settings has multiple levels, Up should navigate up // that hierarchy. Intent intent = new Intent(this, PostListActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); NavUtils.navigateUpTo(this, intent); return true; } return super.onOptionsItemSelected(item); } private static final String KEY_CACHE_SIZE_CALCULATED = "cache_size_calculated"; private static final String KEY_CACHE_SIZE = "cache_size"; private static final String KEY_CACHE_SIZE_MAX = "cache_size_max"; private static final String KEY_MEM_CACHE_SIZE = "mem_cache_size"; private static final String KEY_MEM_CACHE_SIZE_MAX = "mem_cache_size_max"; private static final String KEY_POST_COUNT = "post_count"; private boolean mCacheSizeCalculated = false; private double mCacheSize = -1; private double mMaxCacheSize = -1; private double mMemCacheSize = -1; private double mMaxMemCacheSize = -1; private int mPostCount = -1; @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(KEY_CACHE_SIZE_CALCULATED, mCacheSizeCalculated); outState.putDouble(KEY_CACHE_SIZE, mCacheSize); outState.putDouble(KEY_CACHE_SIZE_MAX, mMaxCacheSize); outState.putDouble(KEY_MEM_CACHE_SIZE, mMemCacheSize); outState.putDouble(KEY_MEM_CACHE_SIZE_MAX, mMaxMemCacheSize); outState.putInt(KEY_POST_COUNT, mPostCount); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); setupSimplePreferencesScreen(); if (savedInstanceState != null) { mCacheSizeCalculated = savedInstanceState.getBoolean(KEY_CACHE_SIZE_CALCULATED, false); mCacheSize = savedInstanceState.getDouble(KEY_CACHE_SIZE, -1); mMaxCacheSize = savedInstanceState.getDouble(KEY_CACHE_SIZE_MAX, -1); mMemCacheSize = savedInstanceState.getDouble(KEY_MEM_CACHE_SIZE, -1); mMaxMemCacheSize = savedInstanceState.getDouble(KEY_MEM_CACHE_SIZE_MAX, -1); mPostCount = savedInstanceState.getInt(KEY_POST_COUNT, -1); } } /** * Shows the simplified settings UI if the device configuration if the * device configuration dictates that a simplified, single-pane UI should be * shown. */ private void setupSimplePreferencesScreen() { if (!isSimplePreferences(this)) return; // Add a empty preference screen so we can insert headers... addPreferencesFromResource(R.xml.pref_empty); // In the simplified UI, fragments are not used at all and we instead // use the older PreferenceActivity APIs. PreferenceCategory fakeHeader; // Add 'screen layout' preferences, and a corresponding header. fakeHeader = new PreferenceCategory(this); fakeHeader.setTitle(R.string.pref_header_screen_layout); getPreferenceScreen().addPreference(fakeHeader); addPreferencesFromResource(R.xml.pref_screen_layout); // Add 'detail view' preference, and a corresponding header. fakeHeader = new PreferenceCategory(this); fakeHeader.setTitle(R.string.pref_header_detail_view); getPreferenceScreen().addPreference(fakeHeader); addPreferencesFromResource(R.xml.pref_detail); // Add 'network policy' preferences, and a corresponding header. fakeHeader = new PreferenceCategory(this); fakeHeader.setTitle(R.string.pref_header_network_policy); getPreferenceScreen().addPreference(fakeHeader); addPreferencesFromResource(R.xml.pref_network_policy); // Add 'debug' preferences, and a corresponding header. fakeHeader = new PreferenceCategory(this); fakeHeader.setTitle(R.string.pref_header_advanced); getPreferenceScreen().addPreference(fakeHeader); addPreferencesFromResource(R.xml.pref_advanced); // Add 'about' preferences, and a corresponding header. fakeHeader = new PreferenceCategory(this); fakeHeader.setTitle(R.string.pref_header_about); getPreferenceScreen().addPreference(fakeHeader); addPreferencesFromResource(R.xml.pref_about); // Bind the summaries of EditText/List/Dialog/Ringtone preferences to // their values. When their values change, their summaries are updated // to reflect the new value, per the Android Design guidelines. bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_COLUMNS_PORTRAIT), 3); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_COLUMNS_LANDSCAPE), 5); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_STICKY_GRID_HEADER), true); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_SHOW_POST_ID), true); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_SHOW_IMAGE_RESOLUTION), true); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_DOWNLOAD_FULLSIZE), false); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_AUTOPLAY_DELAY), 5000); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_STRICT_BANDWIDTH_USAGE), true); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_AGGRESSIVE_PREFETCH_PREVIEW), false); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_ASYNC_IMAGE_LOADER_INDICATOR), false); Preference preference; preference = findPreference(DanbooruGallerySettings.KEY_PREF_CLEAR_CACHE); assert preference != null; preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(final Preference preference) { setProgressBarIndeterminate(true); setProgressBarIndeterminateVisibility(true); preference.setEnabled(false); DanbooruGalleryApplication.clearCacheWithThread(SettingsActivity.this, new DanbooruGalleryApplication.OnCacheClearedCallback() { @Override public void onCacheCleared() { mCacheSizeCalculated = false; new Thread(new CalculateDiskUsageRunnable(preference, new CalculateDiskUsageRunnable.Callbacks() { @Override public void onCalculationDone(double disk_size, double disk_size_max, double mem_size, double mem_size_max, int post_count) { mCacheSizeCalculated = true; mCacheSize = disk_size; mMaxCacheSize = disk_size_max; mMemCacheSize = mem_size; mMaxMemCacheSize = mem_size_max; mPostCount = post_count; setProgressBarIndeterminateVisibility(false); } }, getResources().getString(R.string.pref_description_clear_cache_calculating), getResources().getString(R.string.pref_description_clear_cache_done))) .start(); runOnUiThread(new Runnable() { @Override public void run() { preference.setEnabled(true); } }); } }); return true; } }); if (mCacheSizeCalculated) { preference.setSummary(getResources().getString(R.string.pref_description_clear_cache_done, mCacheSize, mMaxCacheSize, mMemCacheSize, mMaxMemCacheSize, mPostCount)); } else { new Thread(new CalculateDiskUsageRunnable(preference, new CalculateDiskUsageRunnable.Callbacks() { @Override public void onCalculationDone(double disk_size, double disk_size_max, double mem_size, double mem_size_max, int post_count) { mCacheSizeCalculated = true; mCacheSize = disk_size; mMaxCacheSize = disk_size_max; mMemCacheSize = mem_size; mMaxMemCacheSize = mem_size_max; mPostCount = post_count; } }, getResources().getString(R.string.pref_description_clear_cache_calculating), getResources().getString(R.string.pref_description_clear_cache_done))).start(); } if (getResources().getString(R.string.pref_title_translator).trim().isEmpty()) { preference = findPreference(DanbooruGallerySettings.KEY_PREF_TRANSLATOR); getPreferenceScreen().removePreference(preference); } preference = findPreference(DanbooruGallerySettings.KEY_PREF_VERSION); try { PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0); preference.setTitle( getResources().getString(R.string.pref_title_version, pinfo.versionCode, pinfo.versionName)); preference.setSummary(getResources().getString(R.string.pref_description_version, pinfo.versionCode, pinfo.versionName)); } catch (PackageManager.NameNotFoundException ignored) { preference.setTitle(getResources().getString(R.string.pref_title_version, 99999999, "????????")); preference .setSummary(getResources().getString(R.string.pref_description_version, 99999999, "????????")); } } /** {@inheritDoc} */ @Override public boolean onIsMultiPane() { return isXLargeTablet(this) && !isSimplePreferences(this); } /** * Helper method to determine if the device has an extra-large screen. For * example, 10" tablets are extra-large. */ private static boolean isXLargeTablet(Context context) { return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; } private static boolean isSimplePreferences(Context context) { return !isXLargeTablet(context); } /** {@inheritDoc} */ @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void onBuildHeaders(List<Header> target) { if (!isSimplePreferences(this)) { loadHeadersFromResource(R.xml.pref_headers, target); } } /** * A preference value change listener that updates the preference's summary * to reflect its new value. */ private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object value) { if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list. ListPreference listPreference = (ListPreference) preference; int index = listPreference.findIndexOfValue(value.toString()); // Set the summary to reflect the new value. preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null); } return true; } }; /** * Binds a preference's summary to its value. More specifically, when the * preference's value is changed, its summary (line of text below the * preference title) is updated to reflect the value. The summary is also * immediately updated upon calling this method. The exact display format is * dependent on the type of preference. * * @see #sBindPreferenceSummaryToValueListener */ private static void bindPreferenceSummaryToValue(Preference preference, int defaultValue) { // Set the listener to watch for value changes. preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // Trigger the listener immediately with the preference's // current value. try { sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager.getDefaultSharedPreferences(preference.getContext()) .getInt(preference.getKey(), defaultValue)); } catch (ClassCastException ignored) { PreferenceManager.getDefaultSharedPreferences(preference.getContext()).edit() .remove(preference.getKey()).commit(); sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager.getDefaultSharedPreferences(preference.getContext()) .getInt(preference.getKey(), defaultValue)); } } private static void bindPreferenceSummaryToValue(Preference preference, boolean defaultValue) { // Set the listener to watch for value changes. preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // Trigger the listener immediately with the preference's // current value. try { sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager.getDefaultSharedPreferences(preference.getContext()) .getBoolean(preference.getKey(), defaultValue)); } catch (ClassCastException ignored) { PreferenceManager.getDefaultSharedPreferences(preference.getContext()).edit() .remove(preference.getKey()).commit(); sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager.getDefaultSharedPreferences(preference.getContext()) .getBoolean(preference.getKey(), defaultValue)); } } // private static void bindPreferenceSummaryToValue(Preference preference, float defaultValue) // { // // Set the listener to watch for value changes. // preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // // // Trigger the listener immediately with the preference's // // current value. // try // { // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getFloat(preference.getKey(), defaultValue)); // } // catch (ClassCastException ignored) // { // PreferenceManager.getDefaultSharedPreferences(preference.getContext()) // .edit().remove(preference.getKey()).commit(); // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getFloat(preference.getKey(), defaultValue)); // } // } // private static void bindPreferenceSummaryToValue(Preference preference, long defaultValue) // { // // Set the listener to watch for value changes. // preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // // // Trigger the listener immediately with the preference's // // current value. // try // { // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getLong(preference.getKey(), defaultValue)); // } // catch (ClassCastException ignored) // { // PreferenceManager.getDefaultSharedPreferences(preference.getContext()) // .edit().remove(preference.getKey()).commit(); // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getLong(preference.getKey(), defaultValue)); // } // } // private static void bindPreferenceSummaryToValue(Preference preference, String defaultValue) // { // // Set the listener to watch for value changes. // preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // // // Trigger the listener immediately with the preference's // // current value. // try // { // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getString(preference.getKey(), defaultValue)); // } // catch (ClassCastException ignored) // { // PreferenceManager.getDefaultSharedPreferences(preference.getContext()) // .edit().remove(preference.getKey()).commit(); // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getString(preference.getKey(), defaultValue)); // } // } // private static void bindPreferenceSummaryToValue(Preference preference, Set<String> defaultValue) // { // // Set the listener to watch for value changes. // preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // // // Trigger the listener immediately with the preference's // // current value. // try // { // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getStringSet(preference.getKey(), defaultValue)); // } // catch (ClassCastException ignored) // { // PreferenceManager.getDefaultSharedPreferences(preference.getContext()) // .edit().remove(preference.getKey()).commit(); // sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, // PreferenceManager // .getDefaultSharedPreferences(preference.getContext()) // .getStringSet(preference.getKey(), defaultValue)); // } // } /** * This fragment shows screen layout preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class ScreenLayoutPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_screen_layout); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_COLUMNS_PORTRAIT), 3); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_COLUMNS_LANDSCAPE), 5); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_STICKY_GRID_HEADER), true); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_SHOW_POST_ID), true); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_SHOW_IMAGE_RESOLUTION), true); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class DetailViewPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_detail); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_DOWNLOAD_FULLSIZE), false); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_AUTOPLAY_DELAY), 5000); } } /** * This fragment shows notification preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class NetworkPolicyPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_network_policy); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_STRICT_BANDWIDTH_USAGE), true); bindPreferenceSummaryToValue( findPreference(DanbooruGallerySettings.KEY_PREF_AGGRESSIVE_PREFETCH_PREVIEW), false); } } /** * This fragment shows debug preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class AdvancedPreferenceFragment extends PreferenceFragment { private boolean mCacheSizeCalculated = false; private double mCacheSize = -1; private double mMaxCacheSize = -1; private double mMemCacheSize = -1; private double mMaxMemCacheSize = -1; private int mPostCount = -1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_advanced); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue( findPreference(DanbooruGallerySettings.KEY_PREF_ASYNC_IMAGE_LOADER_INDICATOR), false); bindPreferenceSummaryToValue(findPreference(DanbooruGallerySettings.KEY_PREF_CLEAR_CACHE), false); if (savedInstanceState != null) { mCacheSizeCalculated = savedInstanceState.getBoolean(KEY_CACHE_SIZE_CALCULATED, false); mCacheSize = savedInstanceState.getDouble(KEY_CACHE_SIZE, -1); mMaxCacheSize = savedInstanceState.getDouble(KEY_CACHE_SIZE_MAX, -1); } Preference preference = findPreference(DanbooruGallerySettings.KEY_PREF_CLEAR_CACHE); assert preference != null; preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(final Preference preference) { getActivity().setProgressBarIndeterminate(true); getActivity().setProgressBarIndeterminateVisibility(true); DanbooruGalleryApplication.clearCacheWithThread(getActivity(), new DanbooruGalleryApplication.OnCacheClearedCallback() { @Override public void onCacheCleared() { mCacheSizeCalculated = false; new Thread(new CalculateDiskUsageRunnable(preference, new CalculateDiskUsageRunnable.Callbacks() { @Override public void onCalculationDone(double disk_size, double disk_size_max, double mem_size, double mem_size_max, int post_count) { mCacheSizeCalculated = true; mCacheSize = disk_size; mMaxCacheSize = disk_size_max; mMemCacheSize = mem_size; mMaxMemCacheSize = mem_size_max; mPostCount = post_count; getActivity().setProgressBarIndeterminateVisibility(false); } }, getResources() .getString(R.string.pref_description_clear_cache_calculating), getResources().getString(R.string.pref_description_clear_cache_done))) .start(); } }); return true; } }); if (mCacheSizeCalculated) { preference.setSummary(getResources().getString(R.string.pref_description_clear_cache_done, mCacheSize, mMaxCacheSize, mMemCacheSize, mMaxMemCacheSize, mPostCount)); } else { new Thread(new CalculateDiskUsageRunnable(preference, new CalculateDiskUsageRunnable.Callbacks() { @Override public void onCalculationDone(double disk_size, double disk_size_max, double mem_size, double mem_size_max, int post_count) { mCacheSizeCalculated = true; mCacheSize = disk_size; mMaxCacheSize = disk_size_max; mMemCacheSize = mem_size; mMaxMemCacheSize = mem_size_max; mPostCount = post_count; } }, getResources().getString(R.string.pref_description_clear_cache_calculating), getResources().getString(R.string.pref_description_clear_cache_done))).start(); } } } /** * This fragment shows about preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class AboutPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_about); Preference preference; if (getResources().getString(R.string.pref_title_translator).trim().isEmpty()) { preference = findPreference(DanbooruGallerySettings.KEY_PREF_TRANSLATOR); getPreferenceScreen().removePreference(preference); } preference = findPreference(DanbooruGallerySettings.KEY_PREF_VERSION); try { PackageInfo pinfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); preference.setTitle(getResources().getString(R.string.pref_title_version, pinfo.versionCode, pinfo.versionName)); preference.setSummary(getResources().getString(R.string.pref_description_version, pinfo.versionCode, pinfo.versionName)); } catch (PackageManager.NameNotFoundException ignored) { preference.setTitle(getResources().getString(R.string.pref_title_version, 99999999, "????????")); preference.setSummary( getResources().getString(R.string.pref_description_version, 99999999, "????????")); } } } private static class CalculateDiskUsageRunnable implements Runnable { public interface Callbacks { public void onCalculationDone(double disk_size, double disk_size_max, double mem_size, double mem_size_max, int post_count); } private double disk_size = 0; private double disk_size_max = 0; private double mem_size = 0; private double mem_size_max = 0; private int post_count = 0; private String mMessage; private String mMessageDone; private Callbacks mCallbacks; private Preference mPreference; private Handler mHandler = new Handler(); public CalculateDiskUsageRunnable(Preference preference, Callbacks callbacks, String message, String messageDone) { mPreference = preference; mCallbacks = callbacks; mMessage = message; mMessageDone = messageDone; } long accumulateDiskSizeRecursive(File file) { if (!file.exists()) { synchronized (mUpdateRunnable) { mHandler.removeCallbacks(mUpdateRunnable); mHandler.post(mUpdateRunnable); } return 0; } if (file.isFile()) { disk_size = file.length() / 1024.0 / 1024.0; synchronized (mUpdateRunnable) { mHandler.removeCallbacks(mUpdateRunnable); mHandler.post(mUpdateRunnable); } return file.length(); } if (file.isDirectory()) { long ret = file.length(); File[] children = file.listFiles(); if (children != null) for (File child : children) { ret += accumulateDiskSizeRecursive(child); disk_size = ret / 1024.0 / 1024.0; synchronized (mUpdateRunnable) { mHandler.removeCallbacks(mUpdateRunnable); mHandler.post(mUpdateRunnable); } } return ret; } throw new IllegalArgumentException( "The file " + file.getAbsolutePath() + " is not a file nor a directory."); } private final Runnable mUpdateRunnable = new Runnable() { @Override public void run() { try { mPreference.setSummary( String.format(mMessage, disk_size, disk_size_max, mem_size, mem_size_max, post_count)); } catch (IllegalStateException ignored) { } } }; @Override public void run() { mem_size = Picasso.getMemCache().size() / 1024.0 / 1024.0; mem_size_max = Picasso.getMemCache().maxSize() / 1024.0 / 1024.0; post_count = PostsTable.getPostCount(); mHandler.post(mUpdateRunnable); File cache = Picasso.getCacheDir(); disk_size_max = Picasso.calculateDiskCacheSize(cache) / 1024.0 / 1024.0; mHandler.removeCallbacks(mUpdateRunnable); mHandler.post(mUpdateRunnable); disk_size = accumulateDiskSizeRecursive(cache) / 1024.0 / 1024.0; mMessage = mMessageDone; mHandler.removeCallbacks(mUpdateRunnable); mHandler.post(mUpdateRunnable); mCallbacks.onCalculationDone(disk_size, disk_size_max, mem_size, mem_size_max, post_count); } } }