package com.vaguehope.onosendai.ui.pref; import java.io.File; import java.io.PrintWriter; import java.util.List; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import com.vaguehope.onosendai.config.Column; import com.vaguehope.onosendai.config.Config; import com.vaguehope.onosendai.config.ConfigBuilder; import com.vaguehope.onosendai.config.InternalColumnType; import com.vaguehope.onosendai.config.Prefs; import com.vaguehope.onosendai.model.Meta; import com.vaguehope.onosendai.model.Tweet; import com.vaguehope.onosendai.storage.DbBindingAsyncTask; import com.vaguehope.onosendai.storage.DbInterface; import com.vaguehope.onosendai.storage.DbInterface.Selection; import com.vaguehope.onosendai.update.CleanupService; import com.vaguehope.onosendai.util.DialogHelper; import com.vaguehope.onosendai.util.IoHelper; import com.vaguehope.onosendai.util.LogWrapper; import com.vaguehope.onosendai.util.LogcatHelper; public class AdvancedPrefFragment extends PreferenceFragment { public static final String KEY_THREAD_INSPECTOR = "pref_adv_thread_inspector"; private static final LogWrapper LOG = new LogWrapper("ADVPREF"); private Prefs prefs; @Override public void onCreate (final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity())); this.prefs = new Prefs(getPreferenceManager()); addEntries(); } protected Prefs getPrefs () { return this.prefs; } private void addEntries () { addThreadInspector(); addImportConfPref(); addExportConfPref(); addDumpLogPref(); addDumpReadLaterPref(); addHousekeepPref(); } private void addThreadInspector () { final CheckBoxPreference pref = new CheckBoxPreference(getActivity()); pref.setKey(KEY_THREAD_INSPECTOR); pref.setTitle("Thread Inspector"); //ES pref.setSummary("For debugging issues with worker threads."); //ES getPreferenceScreen().addPreference(pref); } private void addImportConfPref () { final Preference pref = new Preference(getActivity()); pref.setTitle("Import deck.conf"); //ES if (Config.isConfigFilePresent()) { pref.setSummary("Replace existing configuration"); //ES pref.setOnPreferenceClickListener(this.importClickListener); } else { pref.setSummary("File not found: " + Config.configFile().getAbsolutePath()); pref.setEnabled(false); } getPreferenceScreen().addPreference(pref); } private void addExportConfPref () { final Preference pref = new Preference(getActivity()); pref.setTitle("Export deck.conf (without secrets)"); //ES pref.setSummary("Write to /sdcard/deck.<time>.conf"); //ES pref.setOnPreferenceClickListener(this.exportClickListener); getPreferenceScreen().addPreference(pref); } private void addDumpLogPref () { final Preference pref = new Preference(getActivity()); pref.setTitle("Dump log"); //ES pref.setSummary("Write app log to /sdcard/onosendai-<time>.log"); //ES pref.setOnPreferenceClickListener(this.dumpLogsClickListener); getPreferenceScreen().addPreference(pref); } private void addDumpReadLaterPref () { final Preference pref = new Preference(getActivity()); pref.setTitle("Dump read later"); //ES pref.setSummary("Write read later column to /sdcard/reading-<time>.txt"); //ES pref.setOnPreferenceClickListener(this.dumpReadLaterListener); getPreferenceScreen().addPreference(pref); } private void addHousekeepPref () { final Preference pref = new Preference(getActivity()); pref.setTitle("Housekeep"); //ES pref.setSummary("Housekeep things now. Underwhelming."); //ES pref.setOnPreferenceClickListener(this.housekeepListener); getPreferenceScreen().addPreference(pref); } private final OnPreferenceClickListener importClickListener = new OnPreferenceClickListener() { @Override public boolean onPreferenceClick (final Preference preference) { askImport(); return true; } }; private final OnPreferenceClickListener exportClickListener = new OnPreferenceClickListener() { @Override public boolean onPreferenceClick (final Preference preference) { doExport(); return true; } }; private final OnPreferenceClickListener dumpLogsClickListener = new OnPreferenceClickListener() { @Override public boolean onPreferenceClick (final Preference preference) { dumpLog(); return true; } }; private final OnPreferenceClickListener dumpReadLaterListener = new OnPreferenceClickListener() { @Override public boolean onPreferenceClick (final Preference preference) { dumpReadLater(); return true; } }; private final OnPreferenceClickListener housekeepListener = new OnPreferenceClickListener() { @Override public boolean onPreferenceClick (final Preference preference) { housekeep(); return true; } }; protected void askImport () { DialogHelper.askYesNo(getActivity(), "Are you sure you want to overwrite all configuration?", //ES new Runnable() { @Override public void run () { doImport(); } }); } protected void doImport () { try { final Config config = Config.getConfig(); new ConfigBuilder() .config(config) .writeOverMain(getActivity()); final int accountsWithoutSecrets = config.countAccountsWithoutSecrets(); if (accountsWithoutSecrets > 0) DialogHelper.alert(getActivity(), String.format( "%s accounts imported are missing secrets. You must add them before things will work again.", accountsWithoutSecrets)); //ES } catch (final Exception e) { // NOSONAR show user all errors. LOG.e("Failed to import configuration.", e); DialogHelper.alertAndClose(getActivity(), e); } } protected void doExport () { try { final File file = new File(Environment.getExternalStorageDirectory(), "deck." + System.currentTimeMillis() + ".conf"); IoHelper.stringToFile(this.prefs.asConfig().toJson().toString(2), file); DialogHelper.alert(getActivity(), "Written to:\n" + file.getAbsolutePath()); //ES } catch (final Exception e) { // NOSONAR show user all errors. LOG.e("Failed to export configuration.", e); DialogHelper.alertAndClose(getActivity(), e); } } protected void dumpLog () { try { final File file = new File(Environment.getExternalStorageDirectory(), "onosendai-" + System.currentTimeMillis() + ".log"); new DumpLog(getActivity(), file).execute(); } catch (final Exception e) { // NOSONAR show user all errors. LOG.e("Failed to dump log.", e); DialogHelper.alert(getActivity(), e); } } protected void dumpReadLater () { try { final File file = new File(Environment.getExternalStorageDirectory(), "reading-" + System.currentTimeMillis() + ".txt"); new DumpReadLater(getActivity(), this.prefs.asConfig(), file).execute(); } catch (final Exception e) { // NOSONAR show user all errors. LOG.e("Failed to dump read later.", e); DialogHelper.alert(getActivity(), e); } } protected void housekeep () { new Housekeep(getActivity()).execute(); } private static class DumpLog extends AsyncTask<Void, Void, Exception> { private final Context context; private final File file; private ProgressDialog dialog; public DumpLog (final Context context, final File file) { this.context = context; this.file = file; } @Override protected void onPreExecute () { this.dialog = ProgressDialog.show(this.context, "Log", "Saving...", true); //ES } @Override protected Exception doInBackground (final Void... params) { try { LogcatHelper.dumpLog(this.file); return null; } catch (final Exception e) { // NOSONAR show user all errors. return e; } } @Override protected void onPostExecute (final Exception result) { this.dialog.dismiss(); if (result == null) { DialogHelper.alert(this.context, "Log written to:\n" + this.file.getAbsolutePath()); //ES } else { LOG.e("Failed to dump read later.", result); DialogHelper.alert(this.context, result); } } } private static class DumpReadLater extends DbBindingAsyncTask<Void, Void, Exception> { private final Config conf; private final File file; private ProgressDialog dialog; public DumpReadLater (final Context context, final Config config, final File file) { super(null, context); this.conf = config; this.file = file; } @Override protected LogWrapper getLog () { return LOG; } @Override protected void onPreExecute () { this.dialog = ProgressDialog.show(getContext(), "Read Later", "Saving...", true); //ES } @Override protected Exception doInBackgroundWithDb (final DbInterface db, final Void... params) { final Column col = this.conf.findInternalColumn(InternalColumnType.LATER); final List<Tweet> ts = db.getTweets(col.getId(), 500, Selection.ALL); // FIXME extract to constant. try { final PrintWriter w = new PrintWriter(this.file, "UTF-8"); try { for (final Tweet tw : ts) { final Tweet t = db.getTweetDetails(col.getId(), tw); w.append(t.getSid()).append(":").append(String.valueOf(t.getTime())).println(); w.append(t.getUsername()).append(":").append(t.getFullname()).println(); w.append(t.getBody()).println(); if (t.getMetas() != null) for (final Meta m : t.getMetas()) { w.append(m.getType().toString()).append(":").append(m.getTitle()).append(":").append(m.getData()).println(); } w.println(); } return null; } finally { IoHelper.closeQuietly(w); } } catch (final Exception e) { // NOSONAR show user all errors. return e; } } @Override protected void onPostExecute (final Exception result) { this.dialog.dismiss(); if (result == null) { DialogHelper.alert(getContext(), "Read later column written to:\n" + this.file.getAbsolutePath()); //ES } else { LOG.e("Failed to dump read later.", result); DialogHelper.alert(getContext(), result); } } } private static class Housekeep extends DbBindingAsyncTask<Void, Void, Exception> { private ProgressDialog dialog; public Housekeep (final Context context) { super(null, context); } @Override protected LogWrapper getLog () { return LOG; } @Override protected void onPreExecute () { this.dialog = ProgressDialog.show(getContext(), "Housekeep", "Please wait...", true); //ES } @Override protected Exception doInBackgroundWithDb (final DbInterface db, final Void... params) { try { CleanupService.clean(getContext(), db); return null; } catch (final Exception e) { // NOSONAR show user all errors. return e; } } @Override protected void onPostExecute (final Exception result) { this.dialog.dismiss(); if (result == null) { DialogHelper.alert(getContext(), "Housekeep complete."); //ES } else { LOG.e("Failed to housekeep.", result); DialogHelper.alert(getContext(), result); } } } }