Advertisement
Guest User

MessageList Activity

a guest
Sep 20th, 2014
380
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 167.50 KB | None | 0 0
  1. import java.io.File;
  2. import java.io.FileNotFoundException;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.Calendar;
  8. import java.util.Collection;
  9. import java.util.Collections;
  10. import java.util.EnumSet;
  11. import java.util.HashSet;
  12. import java.util.LinkedList;
  13. import java.util.List;
  14. import java.util.Locale;
  15. import java.util.Set;
  16. import java.util.concurrent.ConcurrentHashMap;
  17.  
  18. import android.annotation.SuppressLint;
  19. import android.app.Activity;
  20. import android.app.AlertDialog;
  21. import android.app.Application;
  22. import android.app.Dialog;
  23. import android.app.FragmentManager;
  24. import android.app.FragmentManager.OnBackStackChangedListener;
  25. import android.app.FragmentTransaction;
  26. import android.app.ProgressDialog;
  27. import android.app.SearchManager;
  28. import android.content.BroadcastReceiver;
  29. import android.content.ContentResolver;
  30. import android.content.Context;
  31. import android.content.DialogInterface;
  32. import android.content.DialogInterface.OnMultiChoiceClickListener;
  33. import android.content.Intent;
  34. import android.content.IntentFilter;
  35. import android.content.SharedPreferences;
  36. import android.content.SharedPreferences.Editor;
  37. import android.content.pm.PackageInfo;
  38. import android.content.pm.PackageManager;
  39. import android.content.pm.PackageManager.NameNotFoundException;
  40. import android.content.pm.ResolveInfo;
  41. import android.content.res.Configuration;
  42. import android.database.ContentObserver;
  43. import android.database.Cursor;
  44. import android.net.Uri;
  45. import android.os.AsyncTask;
  46. import android.os.Build;
  47. import android.os.Bundle;
  48. import android.os.Handler;
  49. import android.os.PowerManager;
  50. import android.support.v4.app.ActionBarDrawerToggle;
  51. import android.support.v4.view.GravityCompat;
  52. import android.support.v4.widget.DrawerLayout;
  53. import android.text.Editable;
  54. import android.text.TextUtils.TruncateAt;
  55. import android.text.TextWatcher;
  56. import android.text.format.DateUtils;
  57. import android.util.Log;
  58. import android.util.SparseBooleanArray;
  59. import android.view.ContextMenu;
  60. import android.view.ContextMenu.ContextMenuInfo;
  61. import android.view.Gravity;
  62. import android.view.KeyEvent;
  63. import android.view.LayoutInflater;
  64. import android.view.Menu;
  65. import android.view.MenuItem;
  66. import android.view.MotionEvent;
  67. import android.view.View;
  68. import android.view.View.OnClickListener;
  69. import android.view.ViewGroup;
  70. import android.view.Window;
  71. import android.view.animation.AnimationUtils;
  72. import android.webkit.WebView;
  73. import android.widget.AdapterView;
  74. import android.widget.AdapterView.AdapterContextMenuInfo;
  75. import android.widget.AdapterView.OnItemClickListener;
  76. import android.widget.ArrayAdapter;
  77. import android.widget.BaseAdapter;
  78. import android.widget.CheckBox;
  79. import android.widget.CompoundButton;
  80. import android.widget.CompoundButton.OnCheckedChangeListener;
  81. import android.widget.EditText;
  82. import android.widget.Filter;
  83. import android.widget.Filterable;
  84. import android.widget.ImageButton;
  85. import android.widget.LinearLayout;
  86. import android.widget.ListAdapter;
  87. import android.widget.ListView;
  88. import android.widget.ProgressBar;
  89. import android.widget.RelativeLayout;
  90. import android.widget.ScrollView;
  91. import android.widget.TextView;
  92. import android.widget.Toast;
  93.  
  94. import com.commonsware.cwac.merge.MergeAdapter;
  95. import com.fsck.k9.Account;
  96. import com.fsck.k9.Account.FolderMode;
  97. import com.fsck.k9.Account.SortType;
  98. import com.fsck.k9.AccountStats;
  99. import com.fsck.k9.BaseAccount;
  100. import com.fsck.k9.FontSizes;
  101. import com.fsck.k9.K9;
  102. import com.fsck.k9.K9.SplitViewMode;
  103. import com.fsck.k9.Preferences;
  104. import com.fsck.k9.R;
  105. import com.fsck.k9.activity.misc.ExtendedAsyncTask;
  106. import com.fsck.k9.activity.misc.NonConfigurationInstance;
  107. import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
  108. import com.fsck.k9.activity.setup.AccountSettings;
  109. import com.fsck.k9.activity.setup.AccountSetupBasics;
  110. import com.fsck.k9.activity.setup.FolderSettings;
  111. import com.fsck.k9.activity.setup.Prefs;
  112. import com.fsck.k9.activity.setup.WelcomeMessage;
  113. import com.fsck.k9.controller.MessagingController;
  114. import com.fsck.k9.controller.MessagingListener;
  115. import com.fsck.k9.crypto.PgpData;
  116. import com.fsck.k9.fragment.MessageListFragment;
  117. import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener;
  118. import com.fsck.k9.fragment.MessageViewFragment;
  119. import com.fsck.k9.fragment.MessageViewFragment.MessageViewFragmentListener;
  120. import com.fsck.k9.helper.SizeFormatter;
  121. import com.fsck.k9.helper.power.TracingPowerManager;
  122. import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
  123. import com.fsck.k9.mail.Folder;
  124. import com.fsck.k9.mail.Message;
  125. import com.fsck.k9.mail.MessagingException;
  126. import com.fsck.k9.mail.ServerSettings;
  127. import com.fsck.k9.mail.Store;
  128. import com.fsck.k9.mail.Transport;
  129. import com.fsck.k9.mail.store.LocalStore.LocalFolder;
  130. import com.fsck.k9.mail.store.StorageManager;
  131. import com.fsck.k9.mail.store.WebDavStore;
  132. import com.fsck.k9.preferences.SettingsExporter;
  133. import com.fsck.k9.preferences.SettingsImportExportException;
  134. import com.fsck.k9.preferences.SettingsImporter;
  135. import com.fsck.k9.preferences.SettingsImporter.AccountDescription;
  136. import com.fsck.k9.preferences.SettingsImporter.AccountDescriptionPair;
  137. import com.fsck.k9.preferences.SettingsImporter.ImportContents;
  138. import com.fsck.k9.preferences.SettingsImporter.ImportResults;
  139. import com.fsck.k9.search.LocalSearch;
  140. import com.fsck.k9.search.SearchAccount;
  141. import com.fsck.k9.search.SearchSpecification;
  142. import com.fsck.k9.search.SearchSpecification.Attribute;
  143. import com.fsck.k9.search.SearchSpecification.SearchCondition;
  144. import com.fsck.k9.search.SearchSpecification.Searchfield;
  145. import com.fsck.k9.service.MailService;
  146. import com.fsck.k9.view.ColorChip;
  147. import com.fsck.k9.view.MessageHeader;
  148. import com.fsck.k9.view.MessageOpenPgpView;
  149. import com.fsck.k9.view.MessageTitleView;
  150. import com.fsck.k9.view.ViewSwitcher;
  151. import com.fsck.k9.view.ViewSwitcher.OnSwitchCompleteListener;
  152.  
  153. import de.cketti.library.changelog.ChangeLog;
  154.  
  155. /**
  156.  * MessageList is the primary user interface for the program. This Activity
  157.  * shows a list of messages. From this Activity the user can perform all
  158.  * standard message operations.
  159.  */
  160. public class MessageList extends K9ListActivity implements OnItemClickListener,
  161.         MessageListFragmentListener, MessageViewFragmentListener,
  162.         OnBackStackChangedListener, OnSwipeGestureListener,
  163.         OnSwitchCompleteListener {
  164.  
  165.     private static final BaseAccount[] EMPTY_BASE_ACCOUNT_ARRAY = new BaseAccount[0];
  166.  
  167.     /**
  168.      * URL used to open Android Market application
  169.      */
  170.     private static final String ANDROID_MARKET_URL = "https://play.google.com/store/apps/details?id=org.openintents.filemanager";
  171.  
  172.     /**
  173.      * Number of special accounts ('Unified Inbox' and 'All Messages')
  174.      */
  175.     private static final int SPECIAL_ACCOUNTS_COUNT = 2;
  176.  
  177.     private ConcurrentHashMap<BaseAccount, String> pendingWork = new ConcurrentHashMap<BaseAccount, String>();
  178.  
  179.     // for this activity
  180.     private static final String EXTRA_SEARCH = "search";
  181.     private static final String EXTRA_NO_THREADING = "no_threading";
  182.  
  183.     private static final String ACTION_SHORTCUT = "shortcut";
  184.     private static final String EXTRA_SPECIAL_FOLDER = "special_folder";
  185.  
  186.     private static final String EXTRA_MESSAGE_REFERENCE = "message_reference";
  187.  
  188.     // used for remote search
  189.     public static final String EXTRA_SEARCH_ACCOUNT = "com.fsck.k9.search_account";
  190.     private static final String EXTRA_SEARCH_FOLDER = "com.fsck.k9.search_folder";
  191.  
  192.     private static final String STATE_DISPLAY_MODE = "displayMode";
  193.     private static final String STATE_MESSAGE_LIST_WAS_DISPLAYED = "messageListWasDisplayed";
  194.  
  195.     // Used for navigating to next/previous message
  196.     private static final int PREVIOUS = 1;
  197.     private static final int NEXT = 2;
  198.  
  199.     private ArrayList<Object> mList = new ArrayList<Object>();
  200.  
  201.     private static final String EXTRA_ACCOUNT = "account";
  202.  
  203.     private static final String EXTRA_FROM_SHORTCUT = "fromShortcut";
  204.  
  205.     private static final boolean REFRESH_REMOTE = true;
  206.  
  207.     private static ListView mListView;
  208.  
  209.     private FolderListAdapter mAdapter;
  210.  
  211.     private LayoutInflater mInflater;
  212.  
  213.     private ProgressDialog progress;
  214.  
  215.     private static final String TAG = "K9MailExtension";
  216.  
  217.     public static final String PREF_NAME = "pref_name";
  218.  
  219.     static final Uri k9AccountsUri = Uri
  220.             .parse("content://com.fsck.k9.messageprovider/accounts/");
  221.     static final String k9UnreadUri = "content://com.fsck.k9.messageprovider/account_unread/";
  222.     static final String k9MessageProvider = "content://com.fsck.k9.messageprovider/";
  223.  
  224.     ContentObserver contentObserver = null;
  225.     BroadcastReceiver receiver = null;
  226.     IntentFilter filter = null;
  227.  
  228.     private Object mSelectedAccountItem1;
  229.  
  230.     private View header_folders;
  231.  
  232.     private View header_inbox;
  233.  
  234.     private View header_drawer;
  235.  
  236.     private AccountsAdapter1 mAdapter_Accounts;
  237.  
  238.     private ConcurrentHashMap<String, AccountStats> accountStats = new ConcurrentHashMap<String, AccountStats>();
  239.  
  240.     private Accounts mAccounts;
  241.  
  242.     private FontSizes mFontSizes = K9.getFontSizes();
  243.     private Context context;
  244.  
  245.     private MenuItem mRefreshMenuItem;
  246.     private View mActionBarProgressView;
  247.  
  248.     private StorageManager.StorageListener mStorageListener = new StorageListenerImplementation();
  249.  
  250.     private android.app.ActionBar mActionBar;
  251.     private View mActionBarMessageList;
  252.     private View mActionBarMessageView;
  253.     private MessageTitleView mActionBarSubject;
  254.     private TextView mActionBarTitle;
  255.     private TextView mActionBarSubTitle;
  256.     private TextView mActionBarUnread;
  257.     private android.view.Menu mMenu;
  258.  
  259.     DrawerLayout mDrawerLayout;
  260.     LinearLayout mDrawerLinear;
  261.  
  262.     TextView mWelcomePerson;
  263.     ListView mDrawerList;
  264.     ListView mDrawerList_Inbox;
  265.  
  266.     public static ActionBarDrawerToggle mDrawerToggle;
  267.  
  268.     String actionbar_colors, background_colorsString;
  269.     private String Show_View;
  270.     String[] title;
  271.     String[] count;
  272.     int[] icon;
  273.     String[] title_Inbox;
  274.     String[] count_Inbox;
  275.     int[] icon_Inbox;
  276.     private String counterss;
  277.     private int counters;
  278.  
  279.     private CharSequence mDrawerTitle;
  280.     private CharSequence mTitle;
  281.  
  282.     private int shared1;
  283.  
  284.     private BaseAccount mBaseAccount;
  285.  
  286.     private int countersss1;
  287.  
  288.     private int mUnreadMessageCount = 0;
  289.  
  290.     private String due_tommorow_shared, due_tommorow_shared_content;
  291.  
  292.     private List<String> read_due_today_list;
  293.  
  294.     private String K9count;
  295.  
  296.     private View swipe;
  297.  
  298.     private int shared;
  299.  
  300.     private int countersss;
  301.  
  302.     private ViewGroup mMessageViewContainer;
  303.     private View mMessageViewPlaceHolder;
  304.  
  305.     private MessageListFragment mMessageListFragment;
  306.     private MessageViewFragment mMessageViewFragment;
  307.     private int mFirstBackStackId = -1;
  308.  
  309.     private ScrollView mDrawer_Scroll;
  310.  
  311.     private Account mAccount;
  312.     private String mFolderName;
  313.     private LocalSearch mSearch;
  314.     private boolean mSingleFolderMode;
  315.     private boolean mSingleAccountMode;
  316.  
  317.     private String[] Accountsone;
  318.     private String[] BeaconPortaltwo;
  319.     private String[] Foldersthree;
  320.  
  321.     int[] mAccountsHeights;
  322.     int[] mBeaconPortalHeights;
  323.     int[] mFoldersHeights;
  324.  
  325.     private K9FragmentActivity mK9FragmentActivity;
  326.  
  327.     private K9ActivityCommon mBase;
  328.  
  329.     private BaseAccount mSelectedContextAccount;
  330.  
  331.     private ProgressBar mActionBarProgress;
  332.     private android.view.MenuItem mMenuButtonCheckMail;
  333.     private View mActionButtonIndeterminateProgress;
  334.     private int mLastDirection = (K9.messageViewShowNext()) ? NEXT : PREVIOUS;
  335.  
  336.     /**
  337.      * {@code true} if the message list should be displayed as flat list (i.e.
  338.      * no threading) regardless whether or not message threading was enabled in
  339.      * the settings. This is used for filtered views, e.g. when only displaying
  340.      * the unread messages in a folder.
  341.      */
  342.     private boolean mNoThreading;
  343.  
  344.     private String K9counts;
  345.  
  346.     private MessageList currentActivity;
  347.  
  348.     private DisplayMode mDisplayMode;
  349.     private MessageReference mMessageReference;
  350.  
  351.     /**
  352.      * {@code true} when the message list was displayed once. This is used in
  353.      * {@link #onBackPressed()} to decide whether to go from the message view to
  354.      * the message list or finish the activity.
  355.      */
  356.     private boolean mMessageListWasDisplayed = false;
  357.     private ViewSwitcher mViewSwitcher;
  358.  
  359.     private FolderListHandler mHandler = new FolderListHandler();
  360.  
  361.     class FolderListHandler extends Handler {
  362.  
  363.         public void refreshTitle() {
  364.             runOnUiThread(new Runnable() {
  365.                 @Override
  366.                 public void run() {
  367.  
  368.                     if (mUnreadMessageCount == 0) {
  369.  
  370.                     } else {
  371.  
  372.                     }
  373.  
  374.                     String operation = mAdapter.mListener
  375.                             .getOperation(MessageList.this);
  376.                     if (operation.length() < 1) {
  377.  
  378.                     } else {
  379.  
  380.                     }
  381.                 }
  382.             });
  383.         }
  384.  
  385.         public void newFolders(final List<FolderInfoHolder> newFolders) {
  386.             runOnUiThread(new Runnable() {
  387.                 @Override
  388.                 public void run() {
  389.                     mAdapter.mFolders.clear();
  390.                     mAdapter.mFolders.addAll(newFolders);
  391.                     mAdapter.mFilteredFolders = mAdapter.mFolders;
  392.                     mHandler.dataChanged();
  393.                 }
  394.             });
  395.         }
  396.  
  397.         public void workingAccount(final int res) {
  398.             runOnUiThread(new Runnable() {
  399.                 @Override
  400.                 public void run() {
  401.                     String toastText = getString(res, mAccount.getDescription());
  402.                     Toast toast = Toast.makeText(getApplication(), toastText,
  403.                             Toast.LENGTH_SHORT);
  404.                     toast.show();
  405.                 }
  406.             });
  407.         }
  408.  
  409.         public void accountSizeChanged(final long oldSize, final long newSize) {
  410.             runOnUiThread(new Runnable() {
  411.                 @Override
  412.                 public void run() {
  413.                     String toastText = getString(
  414.                             R.string.account_size_changed,
  415.                             mAccount.getDescription(),
  416.                             SizeFormatter.formatSize(getApplication(), oldSize),
  417.                             SizeFormatter.formatSize(getApplication(), newSize));
  418.  
  419.                     Toast toast = Toast.makeText(getApplication(), toastText,
  420.                             Toast.LENGTH_LONG);
  421.                     toast.show();
  422.                 }
  423.             });
  424.         }
  425.  
  426.         public void folderLoading(final String folder, final boolean loading) {
  427.             runOnUiThread(new Runnable() {
  428.                 @Override
  429.                 public void run() {
  430.                     FolderInfoHolder folderHolder = mAdapter.getFolder(folder);
  431.  
  432.                     if (folderHolder != null) {
  433.                         folderHolder.loading = loading;
  434.                     }
  435.  
  436.                 }
  437.             });
  438.         }
  439.  
  440.         public void progress(final boolean progress) {
  441.             // Make sure we don't try this before the menu is initialized
  442.             // this could happen while the activity is initialized.
  443.             if (mRefreshMenuItem == null) {
  444.                 return;
  445.             }
  446.  
  447.             runOnUiThread(new Runnable() {
  448.                 @Override
  449.                 public void run() {
  450.                     if (progress) {
  451.                         mRefreshMenuItem.setActionView(mActionBarProgressView);
  452.                     } else {
  453.                         mRefreshMenuItem.setActionView(null);
  454.                     }
  455.                 }
  456.             });
  457.  
  458.         }
  459.  
  460.         public void dataChanged() {
  461.             runOnUiThread(new Runnable() {
  462.                 @Override
  463.                 public void run() {
  464.                     mAdapter.notifyDataSetChanged();
  465.                     mergeadapter.notifyDataSetChanged();
  466.                 }
  467.             });
  468.         }
  469.     }
  470.  
  471.     /**
  472.      * This class is responsible for reloading the list of local messages for a
  473.      * given folder, notifying the adapter that the message have been loaded and
  474.      * queueing up a remote update of the folder.
  475.      */
  476.  
  477.     private void checkMail(FolderInfoHolder folder) {
  478.         TracingPowerManager pm = TracingPowerManager.getPowerManager(this);
  479.         final TracingWakeLock wakeLock = pm.newWakeLock(
  480.                 PowerManager.PARTIAL_WAKE_LOCK, "FolderList checkMail");
  481.         wakeLock.setReferenceCounted(false);
  482.         wakeLock.acquire(K9.WAKE_LOCK_TIMEOUT);
  483.         MessagingListener listener = new MessagingListener() {
  484.             @Override
  485.             public void synchronizeMailboxFinished(Account account,
  486.                     String folder, int totalMessagesInMailbox,
  487.                     int numNewMessages) {
  488.                 if (!account.equals(mAccount)) {
  489.                     return;
  490.                 }
  491.                 wakeLock.release();
  492.             }
  493.  
  494.             @Override
  495.             public void synchronizeMailboxFailed(Account account,
  496.                     String folder, String message) {
  497.                 if (!account.equals(mAccount)) {
  498.                     return;
  499.                 }
  500.                 wakeLock.release();
  501.             }
  502.         };
  503.         MessagingController.getInstance(getApplication()).synchronizeMailbox(
  504.                 mAccount, folder.name, listener, null);
  505.         sendMail(mAccount);
  506.     }
  507.  
  508.     public static Intent actionHandleAccountIntent(Context context,
  509.             Account account, boolean fromShortcut) {
  510.         Intent intent = new Intent(context, FolderList.class);
  511.         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  512.         intent.putExtra(EXTRA_ACCOUNT, account.getUuid());
  513.  
  514.         if (fromShortcut) {
  515.             intent.putExtra(EXTRA_FROM_SHORTCUT, true);
  516.         }
  517.  
  518.         return intent;
  519.     }
  520.  
  521.     public static void actionHandleAccount(Context context, Account account) {
  522.         Intent intent = actionHandleAccountIntent(context, account, false);
  523.         context.startActivity(intent);
  524.     }
  525.  
  526.     public static void actionDisplaySearch(Context context,
  527.             SearchSpecification search, boolean noThreading, boolean newTask) {
  528.         actionDisplaySearch(context, search, noThreading, newTask, true);
  529.     }
  530.  
  531.     public static void actionDisplaySearch(Context context,
  532.             SearchSpecification search, boolean noThreading, boolean newTask,
  533.             boolean clearTop) {
  534.         context.startActivity(intentDisplaySearch(context, search, noThreading,
  535.                 newTask, clearTop));
  536.     }
  537.  
  538.     public static Intent intentDisplaySearch(Context context,
  539.             SearchSpecification search, boolean noThreading, boolean newTask,
  540.             boolean clearTop) {
  541.         Intent intent = new Intent(context, MessageList.class);
  542.         intent.putExtra(EXTRA_SEARCH, search);
  543.         intent.putExtra(EXTRA_NO_THREADING, noThreading);
  544.  
  545.         if (clearTop) {
  546.             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  547.         }
  548.         if (newTask) {
  549.             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  550.         }
  551.  
  552.         return intent;
  553.     }
  554.  
  555.     public static Intent shortcutIntent(Context context, String specialFolder) {
  556.         Intent intent = new Intent(context, MessageList.class);
  557.         intent.setAction(ACTION_SHORTCUT);
  558.         intent.putExtra(EXTRA_SPECIAL_FOLDER, specialFolder);
  559.         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  560.         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  561.  
  562.         return intent;
  563.     }
  564.  
  565.     public static Intent actionDisplayMessageIntent(Context context,
  566.             MessageReference messageReference) {
  567.         Intent intent = new Intent(context, MessageList.class);
  568.         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  569.         intent.putExtra(EXTRA_MESSAGE_REFERENCE, messageReference);
  570.         return intent;
  571.     }
  572.  
  573.     private enum DisplayMode {
  574.         MESSAGE_LIST, MESSAGE_VIEW, SPLIT_VIEW
  575.     }
  576.  
  577.     private MergeAdapter mergeadapter = null;
  578.  
  579.     private View accounts_view;
  580.  
  581.     private static View folders_view;
  582.  
  583.     private View portals_view;
  584.  
  585.     private SearchAccount mAllMessagesAccount = null;
  586.     private SearchAccount mUnifiedInboxAccount = null;
  587.  
  588.     private static final int DIALOG_REMOVE_ACCOUNT = 1;
  589.     private static final int DIALOG_CLEAR_ACCOUNT = 2;
  590.     private static final int DIALOG_RECREATE_ACCOUNT = 3;
  591.     private static final int DIALOG_NO_FILE_MANAGER = 4;
  592.  
  593.     /**
  594.      * Contains information about objects that need to be retained on
  595.      * configuration changes.
  596.      *
  597.      * @see #onRetainNonConfigurationInstance()
  598.      */
  599.     private NonConfigurationInstance mNonConfigurationInstance;
  600.  
  601.     private static final int ACTIVITY_REQUEST_PICK_SETTINGS_FILE = 1;
  602.  
  603.     public class AccountsHandler extends Handler {
  604.         private void setViewTitle() {
  605.             mActionBarTitle.setText(getString(R.string.accounts_title));
  606.  
  607.             if (mUnreadMessageCount == 0) {
  608.                 mActionBarUnread.setVisibility(View.GONE);
  609.             } else {
  610.                 mActionBarUnread.setText(Integer.toString(mUnreadMessageCount));
  611.                 mActionBarUnread.setVisibility(View.VISIBLE);
  612.             }
  613.  
  614.             String operation = mListener_Accounts
  615.                     .getOperation(MessageList.this);
  616.             operation.trim();
  617.             if (operation.length() < 1) {
  618.                 mActionBarSubTitle.setVisibility(View.GONE);
  619.             } else {
  620.                 mActionBarSubTitle.setVisibility(View.VISIBLE);
  621.                 mActionBarSubTitle.setText(operation);
  622.             }
  623.         }
  624.  
  625.         public void refreshTitle() {
  626.             runOnUiThread(new Runnable() {
  627.                 @Override
  628.                 public void run() {
  629.                     setViewTitle();
  630.                 }
  631.             });
  632.         }
  633.  
  634.         public LocalSearch createUnreadSearch(Context context,
  635.                 BaseAccount account) {
  636.             String searchTitle = context.getString(R.string.search_title,
  637.                     account.getDescription(),
  638.                     context.getString(R.string.unread_modifier));
  639.  
  640.             LocalSearch search;
  641.             if (account instanceof SearchAccount) {
  642.                 search = ((SearchAccount) account).getRelatedSearch().clone();
  643.                 search.setName(searchTitle);
  644.             } else {
  645.                 search = new LocalSearch(searchTitle);
  646.                 search.addAccountUuid(account.getUuid());
  647.  
  648.                 Account realAccount = (Account) account;
  649.                 realAccount.excludeSpecialFolders(search);
  650.                 realAccount.limitToDisplayableFolders(search);
  651.             }
  652.  
  653.             search.and(Searchfield.READ, "1", Attribute.NOT_EQUALS);
  654.  
  655.             return search;
  656.         }
  657.  
  658.         public void dataChanged() {
  659.             runOnUiThread(new Runnable() {
  660.                 @Override
  661.                 public void run() {
  662.                     if (mAdapter_Accounts != null) {
  663.                         mAdapter_Accounts.notifyDataSetChanged();
  664.                         mergeadapter.notifyDataSetChanged();
  665.                     }
  666.                 }
  667.             });
  668.         }
  669.  
  670.         public void workingAccount(final Account account, final int res) {
  671.             runOnUiThread(new Runnable() {
  672.                 @Override
  673.                 public void run() {
  674.                     String toastText = getString(res, account.getDescription());
  675.  
  676.                     Toast toast = Toast.makeText(getApplication(), toastText,
  677.                             Toast.LENGTH_SHORT);
  678.                     toast.show();
  679.                 }
  680.             });
  681.         }
  682.  
  683.         public void accountSizeChanged(final Account account,
  684.                 final long oldSize, final long newSize) {
  685.             runOnUiThread(new Runnable() {
  686.                 @Override
  687.                 public void run() {
  688.                     AccountStats stats = accountStats.get(account.getUuid());
  689.                     if (newSize != -1 && stats != null && K9.measureAccounts()) {
  690.                         stats.size = newSize;
  691.                     }
  692.                     String toastText = getString(
  693.                             R.string.account_size_changed,
  694.                             account.getDescription(),
  695.                             SizeFormatter.formatSize(getApplication(), oldSize),
  696.                             SizeFormatter.formatSize(getApplication(), newSize));
  697.  
  698.                     Toast toast = Toast.makeText(getApplication(), toastText,
  699.                             Toast.LENGTH_LONG);
  700.                     toast.show();
  701.                     if (mAdapter_Accounts != null) {
  702.                         mAdapter_Accounts.notifyDataSetChanged();
  703.                         mergeadapter.notifyDataSetChanged();
  704.                     }
  705.                 }
  706.             });
  707.         }
  708.  
  709.         public void progress_boolean(final boolean progress_boolean) {
  710.             // Make sure we don't try this before the menu is initialized
  711.             // this could happen while the activity is initialized.
  712.             if (mRefreshMenuItem == null) {
  713.                 return;
  714.             }
  715.  
  716.             runOnUiThread(new Runnable() {
  717.                 @Override
  718.                 public void run() {
  719.                     if (progress_boolean) {
  720.                         mRefreshMenuItem
  721.                                 .setActionView(R.layout.actionbar_indeterminate_progress_actionview);
  722.                     } else {
  723.                         mRefreshMenuItem.setActionView(null);
  724.                     }
  725.                 }
  726.             });
  727.  
  728.         }
  729.  
  730.         public void progress_int(final int progress_int) {
  731.             runOnUiThread(new Runnable() {
  732.                 @Override
  733.                 public void run() {
  734.                     getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
  735.                             progress_int);
  736.                 }
  737.             });
  738.         }
  739.     }
  740.  
  741.     public void setProgress_Accounts(boolean progress) {
  742.         mHandler.progress(progress);
  743.     }
  744.  
  745.     ActivityListener mListener_Accounts = new ActivityListener() {
  746.         @Override
  747.         public void informUserOfStatus() {
  748.             mHandler.refreshTitle();
  749.         }
  750.  
  751.         @Override
  752.         public void folderStatusChanged(Account account, String folderName,
  753.                 int unreadMessageCount) {
  754.             try {
  755.                 AccountStats stats = account.getStats(MessageList.this);
  756.                 if (stats == null) {
  757.                     Log.w(K9.LOG_TAG, "Unable to get account stats");
  758.                 } else {
  759.                     accountStatusChanged(account, stats);
  760.                 }
  761.             } catch (Exception e) {
  762.                 Log.e(K9.LOG_TAG, "Unable to get account stats", e);
  763.             }
  764.         }
  765.  
  766.         @Override
  767.         public void accountStatusChanged(BaseAccount account, AccountStats stats) {
  768.             AccountStats oldStats = accountStats.get(account.getUuid());
  769.             int oldUnreadMessageCount = 0;
  770.             if (oldStats != null) {
  771.                 oldUnreadMessageCount = oldStats.unreadMessageCount;
  772.             }
  773.             if (stats == null) {
  774.                 stats = new AccountStats(); // empty stats for unavailable
  775.                                             // accounts
  776.                 stats.available = false;
  777.             }
  778.             accountStats.put(account.getUuid(), stats);
  779.             if (account instanceof Account) {
  780.                 mUnreadMessageCount += stats.unreadMessageCount
  781.                         - oldUnreadMessageCount;
  782.             }
  783.             mHandler.dataChanged();
  784.             pendingWork.remove(account);
  785.  
  786.         }
  787.  
  788.         @Override
  789.         public void synchronizeMailboxFinished(Account account, String folder,
  790.                 int totalMessagesInMailbox, int numNewMessages) {
  791.             MessagingController.getInstance(getApplication()).getAccountStats(
  792.                     MessageList.this, account, mListener_Accounts);
  793.             super.synchronizeMailboxFinished(account, folder,
  794.                     totalMessagesInMailbox, numNewMessages);
  795.  
  796.             mHandler.progress(false);
  797.  
  798.         }
  799.  
  800.         @Override
  801.         public void synchronizeMailboxStarted(Account account, String folder) {
  802.             super.synchronizeMailboxStarted(account, folder);
  803.             mHandler.progress(true);
  804.         }
  805.  
  806.         @Override
  807.         public void synchronizeMailboxFailed(Account account, String folder,
  808.                 String message) {
  809.             super.synchronizeMailboxFailed(account, folder, message);
  810.             mHandler.progress(false);
  811.  
  812.         }
  813.  
  814.     };
  815.  
  816.     private static String ACCOUNT_STATS = "accountStats";
  817.     private static String STATE_UNREAD_COUNT = "unreadCount";
  818.     private static String SELECTED_CONTEXT_ACCOUNT = "selectedContextAccount";
  819.  
  820.     public static final String EXTRA_STARTUP = "startup";
  821.  
  822.     public static final String ACTION_IMPORT_SETTINGS = "importSettings";
  823.  
  824.     public static void listAccounts(Context context) {
  825.         Intent intent = new Intent(context, Accounts.class);
  826.         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  827.                 | Intent.FLAG_ACTIVITY_CLEAR_TOP
  828.                 | Intent.FLAG_ACTIVITY_SINGLE_TOP
  829.                 | Intent.FLAG_ACTIVITY_CLEAR_TASK);
  830.         intent.putExtra(EXTRA_STARTUP, false);
  831.         context.startActivity(intent);
  832.     }
  833.  
  834.     public static void importSettings(Context context) {
  835.         Intent intent = new Intent(context, Accounts.class);
  836.         intent.setAction(ACTION_IMPORT_SETTINGS);
  837.         context.startActivity(intent);
  838.     }
  839.  
  840.     @SuppressLint("ResourceAsColor")
  841.     @Override
  842.     public void onCreate(Bundle savedInstanceState) {
  843.         super.onCreate(savedInstanceState);
  844.  
  845.         if (!K9.isHideSpecialAccounts()) {
  846.             createSpecialAccounts();
  847.         }
  848.  
  849.         Account[] accounts = Preferences.getPreferences(this).getAccounts();
  850.         Intent intent = getIntent();
  851.         // onNewIntent(intent);
  852.  
  853.         // see if we should show the welcome message
  854.         if (ACTION_IMPORT_SETTINGS.equals(intent.getAction())) {
  855.             mAccounts.onImport();
  856.         } else if (accounts.length < 1) {
  857.             WelcomeMessage.showWelcomeMessage(this);
  858.             finish();
  859.             return;
  860.         }
  861.  
  862.         if (UpgradeDatabases.actionUpgradeDatabases(this, intent)) {
  863.             finish();
  864.             return;
  865.         }
  866.  
  867.         requestWindowFeature(Window.FEATURE_PROGRESS);
  868.  
  869.         Log.d(TAG, "onCreate()");
  870.  
  871.         String packageName = "com.fsck.k9";
  872.  
  873.         int versionNumber = 0;
  874.  
  875.         try {
  876.             PackageInfo pi = getApplicationContext().getPackageManager()
  877.                     .getPackageInfo(packageName, PackageManager.GET_META_DATA);
  878.             versionNumber = pi.versionCode;
  879.             String versionName = pi.versionName;
  880.  
  881.             Log.d(TAG, "K-9 is installed - " + versionNumber + " "
  882.                     + versionName);
  883.  
  884.         } catch (NameNotFoundException e) {
  885.             Log.d(TAG, "K-9 not found");
  886.         }
  887.  
  888.         if (versionNumber <= 1) {
  889.             // Register a listener for broadcasts (needed for the older versions
  890.             // of k9)
  891.             Log.d(TAG, "Initialising BroadcastReceiver for old K-9 version");
  892.             receiver = new BroadcastReceiver() {
  893.                 @Override
  894.                 public void onReceive(Context context, Intent intent) {
  895.                     Log.d(TAG, "receiver.onReceive()");
  896.                     doRefresh();
  897.                 }
  898.             };
  899.  
  900.             filter = new IntentFilter();
  901.             filter.addAction("com.fsck.k9.intent.action.EMAIL_RECEIVED");
  902.             filter.addAction("com.fsck.k9.intent.action.EMAIL_DELETED");
  903.             filter.addDataScheme("email");
  904.             registerReceiver(receiver, filter);
  905.         } else {
  906.             // Register our own content observer, rather than using
  907.             // addWatchContentUris()
  908.             // since DashClock might not have permission to access the database
  909.             Log.d(TAG, "Initialising ContentObserver for new K-9 version");
  910.             contentObserver = new ContentObserver(null) {
  911.                 @Override
  912.                 public void onChange(boolean selfChange) {
  913.                     Log.d(TAG, "contentResolver.onChange()");
  914.                     doRefresh();
  915.                 }
  916.             };
  917.             getContentResolver().registerContentObserver(
  918.                     Uri.parse(k9UnreadUri), true, contentObserver);
  919.         }
  920.  
  921.         doRefresh();
  922.  
  923.         if (UpgradeDatabases.actionUpgradeDatabases(this, getIntent())) {
  924.             finish();
  925.             return;
  926.         }
  927.  
  928.         if (useSplitView()) {
  929.             setContentView(R.layout.split_drawer_main);
  930.         } else {
  931.             setContentView(R.layout.drawer);
  932.             mViewSwitcher = (ViewSwitcher) findViewById(R.id.container);
  933.             mViewSwitcher.setFirstInAnimation(AnimationUtils.loadAnimation(
  934.                     this, R.anim.slide_in_left));
  935.             mViewSwitcher.setFirstOutAnimation(AnimationUtils.loadAnimation(
  936.                     this, R.anim.slide_out_right));
  937.             mViewSwitcher.setSecondInAnimation(AnimationUtils.loadAnimation(
  938.                     this, R.anim.slide_in_right));
  939.             mViewSwitcher.setSecondOutAnimation(AnimationUtils.loadAnimation(
  940.                     this, R.anim.slide_out_left));
  941.             mViewSwitcher.setOnSwitchCompleteListener(this);
  942.         }
  943.  
  944.         mergeadapter = new MergeAdapter();
  945.  
  946.         LayoutInflater inflater = getLayoutInflater();
  947.  
  948.         accounts_view = inflater.inflate(R.layout.accounts_list, null);
  949.  
  950.         folders_view = inflater.inflate(R.layout.folders_list, null);
  951.  
  952.         header_folders = inflater.inflate(R.layout.header_folders, null);
  953.  
  954.         initializeActionBar();
  955.  
  956.         mListView = (ListView) findViewById(android.R.id.list);
  957.         // mListView.addHeaderView(header_folders, null, false);
  958.  
  959.         mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
  960.         mListView.setLongClickable(true);
  961.         mListView.setFastScrollEnabled(true);
  962.         mListView.setScrollingCacheEnabled(false);
  963.  
  964.         setResult(RESULT_CANCELED);
  965.  
  966.         mListView.setSaveEnabled(true);
  967.  
  968.         mInflater = getLayoutInflater();
  969.  
  970.         onNewIntent(getIntent());
  971.  
  972.         context = this;
  973.  
  974.         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  975.  
  976.         mDrawerLinear = (LinearLayout) findViewById(R.id.left_drawer);
  977.  
  978.         mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
  979.                 GravityCompat.START);
  980.  
  981.         getListView().setOnItemClickListener(new DrawerItemClickListener());
  982.  
  983.         if (!decodeExtras(getIntent())) {
  984.             return;
  985.         }
  986.  
  987.         findFragments();
  988.         initializeDisplayMode(savedInstanceState);
  989.         initializeLayout();
  990.         initializeFragments();
  991.         displayViews();
  992.         // registerForContextMenu(mDrawerList_Inbox);
  993.         registerForContextMenu(mListView);
  994.  
  995.         getActionBar().setHomeButtonEnabled(true);
  996.         getActionBar().setDisplayHomeAsUpEnabled(true);
  997.  
  998.    
  999.        
  1000.         mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
  1001.                 R.drawable.ic_drawer, R.string.drawer_open,
  1002.                 R.string.drawer_close) {
  1003.  
  1004.             @Override
  1005.             public void onDrawerClosed(View view) {
  1006.                 // TODO Auto-generated method stub
  1007.                 super.onDrawerClosed(view);
  1008.             }
  1009.  
  1010.             @Override
  1011.             public void onDrawerOpened(View drawerView) {
  1012.                 // TODO Auto-generated method stub
  1013.  
  1014.                
  1015.                 super.onDrawerOpened(drawerView);
  1016.             }
  1017.         };
  1018.  
  1019.         mDrawerLayout.setDrawerListener(mDrawerToggle);
  1020.     }
  1021.  
  1022.     private StorageManager.StorageListener storageListener = new StorageManager.StorageListener() {
  1023.  
  1024.         @Override
  1025.         public void onUnmount(String providerId) {
  1026.             refresh();
  1027.         }
  1028.  
  1029.         @Override
  1030.         public void onMount(String providerId) {
  1031.             refresh();
  1032.         }
  1033.     };
  1034.  
  1035.     @Override
  1036.     protected void onPostCreate(Bundle savedInstanceState) {
  1037.         super.onPostCreate(savedInstanceState);
  1038.  
  1039.         mDrawerToggle.syncState();
  1040.     }
  1041.  
  1042.     @Override
  1043.     public void onConfigurationChanged(Configuration newConfig) {
  1044.         super.onConfigurationChanged(newConfig);
  1045.  
  1046.         mDrawerToggle.onConfigurationChanged(newConfig);
  1047.     }
  1048.  
  1049.     @Override
  1050.     public void onResume() {
  1051.         super.onResume();
  1052.  
  1053.         refresh();
  1054.         MessagingController.getInstance(getApplication()).addListener(
  1055.                 mListener_Accounts);
  1056.         StorageManager.getInstance(getApplication()).addListener(
  1057.                 storageListener);
  1058.         mListener_Accounts.onResume(this);
  1059.  
  1060.         new LoadAccounts().execute();
  1061.  
  1062.         // figure out why below if statement throws null later
  1063.  
  1064.         // if (!mAccount.isAvailable(this)) {
  1065.         // Log.i(K9.LOG_TAG,
  1066.         // "account unavaliabale, not showing folder-list but account-list");
  1067.         // Accounts.listAccounts(this);
  1068.         // finish();
  1069.         // return;
  1070.         // }
  1071.         if (mAdapter == null)
  1072.             initializeActivityView();
  1073.  
  1074.         MessagingController.getInstance(getApplication()).addListener(
  1075.                 mAdapter.mListener);
  1076.         // mAccount.refresh(Preferences.getPreferences(this));
  1077.         MessagingController.getInstance(getApplication()).getAccountStats(this,
  1078.                 mAccount, mAdapter.mListener);
  1079.  
  1080.         onRefresh(!REFRESH_REMOTE);
  1081.  
  1082.         MessagingController.getInstance(getApplication()).notifyAccountCancel(
  1083.                 this, mAccount);
  1084.         mAdapter.mListener.onResume(this);
  1085.  
  1086.         if (!(this instanceof Search)) {
  1087.             // necessary b/c no guarantee Search.onStop will be called before
  1088.             // MessageList.onResume
  1089.             // when returning from search results
  1090.             Search.setActive(false);
  1091.         }
  1092.  
  1093.         if (mAccount != null && !mAccount.isAvailable(this)) {
  1094.             onAccountUnavailable();
  1095.             return;
  1096.         }
  1097.         StorageManager.getInstance(getApplication()).addListener(
  1098.                 mStorageListener);
  1099.  
  1100.         // mergeadapter = new MergeAdapter();
  1101.  
  1102.         LayoutInflater inflater = getLayoutInflater();
  1103.  
  1104.         header_folders = inflater.inflate(R.layout.header_folders, null);
  1105.  
  1106.         header_inbox = inflater.inflate(R.layout.header_inbox, null);
  1107.  
  1108.         mListView = getListView();
  1109.  
  1110.         mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
  1111.         mListView.setLongClickable(true);
  1112.         mListView.setFastScrollEnabled(true);
  1113.         mListView.setScrollingCacheEnabled(false);
  1114.  
  1115.         setResult(RESULT_CANCELED);
  1116.  
  1117.         getListView().setSaveEnabled(true);
  1118.  
  1119.         mInflater = getLayoutInflater();
  1120.  
  1121.         context = this;
  1122.  
  1123.         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  1124.  
  1125.         mDrawerLinear = (LinearLayout) findViewById(R.id.left_drawer);
  1126.  
  1127.         mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
  1128.                 GravityCompat.START);
  1129.  
  1130.     }
  1131.  
  1132.     @Override
  1133.     public void onNewIntent(Intent intent) {
  1134.         setIntent(intent); // onNewIntent doesn't autoset our "internal" intent
  1135.  
  1136.         removeFragments();
  1137.  
  1138.         mUnreadMessageCount = 0;
  1139.         String accountUuid = intent.getStringExtra(EXTRA_ACCOUNT);
  1140.         mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
  1141.  
  1142.         // if (mAccount == null) {
  1143.         // // This shouldn't normally happen. But apparently it does. See issue
  1144.         // 2261.
  1145.         // finish();
  1146.         // return;
  1147.         // }
  1148.  
  1149.         if (intent.getBooleanExtra(EXTRA_FROM_SHORTCUT, false)
  1150.                 && !K9.FOLDER_NONE.equals(mAccount.getAutoExpandFolderName())) {
  1151.             onOpenFolder(mAccount.getAutoExpandFolderName());
  1152.             finish();
  1153.         } else {
  1154.             initializeActivityView();
  1155.         }
  1156.  
  1157.         if (mFirstBackStackId >= 0) {
  1158.             getFragmentManager().popBackStackImmediate(mFirstBackStackId,
  1159.                     FragmentManager.POP_BACK_STACK_INCLUSIVE);
  1160.             mFirstBackStackId = -1;
  1161.         }
  1162.         removeMessageListFragment();
  1163.         removeMessageViewFragment();
  1164.  
  1165.         mMessageReference = null;
  1166.         mSearch = null;
  1167.         mFolderName = null;
  1168.  
  1169.         if (!decodeExtras(intent)) {
  1170.             return;
  1171.         }
  1172.  
  1173.         initializeDisplayMode(null);
  1174.         initializeFragments();
  1175.         displayViews();
  1176.         refresh();
  1177.     }
  1178.  
  1179.     private void initializeActivityView() {
  1180.         mAdapter = new FolderListAdapter();
  1181.         restorePreviousData();
  1182.  
  1183.         setListAdapter(mAdapter);
  1184.  
  1185.         getListView().setTextFilterEnabled(mAdapter.getFilter() != null);
  1186.  
  1187.     }
  1188.  
  1189.     @SuppressWarnings("unchecked")
  1190.     private void restorePreviousData() {
  1191.         final Object previousData = getLastNonConfigurationInstance();
  1192.  
  1193.         if (previousData != null) {
  1194.             mAdapter.mFolders = (ArrayList<FolderInfoHolder>) previousData;
  1195.             mAdapter.mFilteredFolders = Collections
  1196.                     .unmodifiableList(mAdapter.mFolders);
  1197.         }
  1198.     }
  1199.  
  1200.     @Override
  1201.     public Object onRetainNonConfigurationInstance() {
  1202.  
  1203.         return (mAdapter == null) ? null : mAdapter.mFolders;
  1204.  
  1205.     }
  1206.  
  1207.     @Override
  1208.     public boolean onKeyDown(int keyCode, KeyEvent event) {
  1209.         // Shortcuts that work no matter what is selected
  1210.         switch (keyCode) {
  1211.         case KeyEvent.KEYCODE_Q: {
  1212.             onAccounts();
  1213.             return true;
  1214.         }
  1215.  
  1216.         case KeyEvent.KEYCODE_S: {
  1217.             onEditAccount();
  1218.             return true;
  1219.         }
  1220.  
  1221.         case KeyEvent.KEYCODE_H: {
  1222.             Toast toast = Toast.makeText(this, R.string.folder_list_help_key,
  1223.                     Toast.LENGTH_LONG);
  1224.             toast.show();
  1225.             return true;
  1226.         }
  1227.  
  1228.         case KeyEvent.KEYCODE_1: {
  1229.             setDisplayMode(FolderMode.FIRST_CLASS);
  1230.             return true;
  1231.         }
  1232.         case KeyEvent.KEYCODE_2: {
  1233.             setDisplayMode(FolderMode.FIRST_AND_SECOND_CLASS);
  1234.             return true;
  1235.         }
  1236.         case KeyEvent.KEYCODE_3: {
  1237.             setDisplayMode(FolderMode.NOT_SECOND_CLASS);
  1238.             return true;
  1239.         }
  1240.         case KeyEvent.KEYCODE_4: {
  1241.             setDisplayMode(FolderMode.ALL);
  1242.             return true;
  1243.         }
  1244.         }// switch
  1245.  
  1246.         return super.onKeyDown(keyCode, event);
  1247.     }// onKeyDown
  1248.  
  1249.     private void setDisplayMode(FolderMode newMode) {
  1250.         mAccount.setFolderDisplayMode(newMode);
  1251.         mAccount.save(Preferences.getPreferences(this));
  1252.         if (mAccount.getFolderPushMode() != FolderMode.NONE) {
  1253.             MailService.actionRestartPushers(this, null);
  1254.         }
  1255.         mAdapter.getFilter().filter(null);
  1256.         onRefresh(false);
  1257.     }
  1258.  
  1259.     private void onRefresh(final boolean forceRemote) {
  1260.  
  1261.         MessagingController.getInstance(getApplication()).listFolders(mAccount,
  1262.                 forceRemote, mAdapter.mListener);
  1263.  
  1264.     }
  1265.  
  1266.     private void onEditPrefs() {
  1267.         Prefs.actionPrefs(this);
  1268.     }
  1269.  
  1270.     private void onEditAccount() {
  1271.         AccountSettings.actionSettings(this, mAccount);
  1272.     }
  1273.  
  1274.     private void onAccounts() {
  1275.         Accounts.listAccounts(this);
  1276.         finish();
  1277.     }
  1278.  
  1279.     private void onEmptyTrash(final Account account) {
  1280.         mHandler.dataChanged();
  1281.  
  1282.         MessagingController.getInstance(getApplication()).emptyTrash(account,
  1283.                 null);
  1284.     }
  1285.  
  1286.     private void onClearFolder(Account account, String folderName) {
  1287.         // There has to be a cheaper way to get at the localFolder object than
  1288.         // this
  1289.         LocalFolder localFolder = null;
  1290.         try {
  1291.             if (account == null || folderName == null
  1292.                     || !account.isAvailable(MessageList.this)) {
  1293.                 Log.i(K9.LOG_TAG, "not clear folder of unavailable account");
  1294.                 return;
  1295.             }
  1296.             localFolder = account.getLocalStore().getFolder(folderName);
  1297.             localFolder.open(Folder.OPEN_MODE_RW);
  1298.             localFolder.clearAllMessages();
  1299.         } catch (Exception e) {
  1300.             Log.e(K9.LOG_TAG, "Exception while clearing folder", e);
  1301.         } finally {
  1302.             if (localFolder != null) {
  1303.                 localFolder.close();
  1304.             }
  1305.         }
  1306.  
  1307.         onRefresh(!REFRESH_REMOTE);
  1308.     }
  1309.  
  1310.     private void sendMail(Account account) {
  1311.         MessagingController.getInstance(getApplication()).sendPendingMessages(
  1312.                 account, mAdapter.mListener);
  1313.     }
  1314.  
  1315.     @Override
  1316.     public boolean onSearchRequested() {
  1317.         Bundle appData = new Bundle();
  1318.         appData.putString(MessageList.EXTRA_SEARCH_ACCOUNT, mAccount.getUuid());
  1319.         startSearch(null, false, appData, false);
  1320.         return true;
  1321.     }
  1322.  
  1323.     private void onOpenFolder(String folder) {
  1324.         LocalSearch search = new LocalSearch(folder);
  1325.         search.addAccountUuid(mAccount.getUuid());
  1326.         search.addAllowedFolder(folder);
  1327.         MessageList.actionDisplaySearch(this, search, false, false);
  1328.     }
  1329.  
  1330.     private void onCompact(Account account) {
  1331.         mHandler.workingAccount(R.string.compacting_account);
  1332.         MessagingController.getInstance(getApplication())
  1333.                 .compact(account, null);
  1334.     }
  1335.  
  1336.     @Override
  1337.     public void onCreateContextMenu(ContextMenu menu, View v,
  1338.             ContextMenuInfo menuInfo) {
  1339.         super.onCreateContextMenu(menu, v, menuInfo);
  1340.  
  1341.         AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
  1342.  
  1343.         if (v == getListView()) {
  1344.  
  1345.             if (info.position > mAdapter_Accounts.getCount()) {
  1346.  
  1347.                 getMenuInflater().inflate(R.menu.folder_context, menu);
  1348.  
  1349.                 FolderInfoHolder folder = (FolderInfoHolder) mAdapter
  1350.                         .getItem(info.position
  1351.                                 - (mAdapter_Accounts.getCount() + 2)); // 2
  1352.                                                                         // seems
  1353.                                                                         // to be
  1354.                                                                         // the
  1355.                 // lucky number here,
  1356.                 // tested with gmail and
  1357.                 // exchange, but i have
  1358.                 // no idea why
  1359.  
  1360.                 menu.setHeaderTitle(folder.displayName);
  1361.  
  1362.             } else if (info.position < mAdapter_Accounts.getCount() + 1) {
  1363.  
  1364.                 menu.setHeaderTitle(R.string.accounts_context_menu_title);
  1365.  
  1366.                 if (mAdapter_Accounts == null) {
  1367.  
  1368.                     Log.d("info =", "mAdapter_Accounts = null");
  1369.  
  1370.                 }
  1371.  
  1372.                 BaseAccount account = (BaseAccount) mergeadapter
  1373.                         .getItem(info.position);
  1374.  
  1375.                 if ((account instanceof Account)
  1376.                         && !((Account) account).isEnabled()) {
  1377.                     getMenuInflater().inflate(R.menu.disabled_accounts_context,
  1378.                             menu);
  1379.                 } else {
  1380.                     getMenuInflater().inflate(R.menu.accounts_context, menu);
  1381.                 }
  1382.  
  1383.                 if (account instanceof SearchAccount) {
  1384.                     for (int i = 0; i < menu.size(); i++) {
  1385.                         android.view.MenuItem item = menu.getItem(i);
  1386.                         item.setVisible(false);
  1387.                     }
  1388.                 } else {
  1389.                     EnumSet<ACCOUNT_LOCATION> accountLocation = accountLocation(account);
  1390.                     if (accountLocation.contains(ACCOUNT_LOCATION.TOP)) {
  1391.                         menu.findItem(R.id.move_up).setEnabled(false);
  1392.                     } else {
  1393.                         menu.findItem(R.id.move_up).setEnabled(true);
  1394.                     }
  1395.                     if (accountLocation.contains(ACCOUNT_LOCATION.BOTTOM)) {
  1396.                         menu.findItem(R.id.move_down).setEnabled(false);
  1397.                     } else {
  1398.                         menu.findItem(R.id.move_down).setEnabled(true);
  1399.                     }
  1400.                 }
  1401.  
  1402.             }
  1403.  
  1404.         }
  1405.     }
  1406.  
  1407.     @Override
  1408.     public boolean onContextItemSelected(android.view.MenuItem item) {
  1409.         AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item
  1410.                 .getMenuInfo();
  1411.  
  1412.         Account realAccount = null;
  1413.  
  1414.         FolderInfoHolder folder = null;
  1415.  
  1416.         if (mListView.getItemAtPosition(menuInfo.position) != null) {
  1417.  
  1418.             if (menuInfo.position - 1 > mAdapter_Accounts.getCount()) {
  1419.  
  1420.                 if (0 < menuInfo.position - (mAdapter_Accounts.getCount())) {
  1421.  
  1422.                     folder = (FolderInfoHolder) mAdapter
  1423.                             .getItem(menuInfo.position
  1424.                                     - (mAdapter_Accounts.getCount() + 2)); // 2
  1425.                                                                             // seems
  1426.                                                                             // to
  1427.                                                                             // be
  1428.                                                                             // the
  1429.                                                                             // lucky
  1430.                                                                             // number,
  1431.                                                                             // tested
  1432.                                                                             // with
  1433.                                                                             // a
  1434.                                                                             // number
  1435.                                                                             // of
  1436.                                                                             // email
  1437.                                                                             // configurations
  1438.  
  1439.                 } else {
  1440.                     folder = (FolderInfoHolder) mAdapter
  1441.                             .getItem(menuInfo.position
  1442.                                     - (mAdapter_Accounts.getCount() + 2));
  1443.  
  1444.                 }
  1445.  
  1446.             } else {
  1447.  
  1448.                 folder = (FolderInfoHolder) mAdapter.getItem(menuInfo.position);
  1449.  
  1450.                 if (menuInfo != null) {
  1451.  
  1452.                     mSelectedContextAccount = (BaseAccount) getListView()
  1453.                             .getItemAtPosition(menuInfo.position);
  1454.                 }
  1455.  
  1456.                 if (mSelectedContextAccount instanceof Account) {
  1457.                     realAccount = (Account) mSelectedContextAccount;
  1458.  
  1459.                 }
  1460.  
  1461.             }
  1462.  
  1463.         }
  1464.  
  1465.         switch (item.getItemId()) {
  1466.         case R.id.clear_local_folder:
  1467.             onClearFolder(mAccount, folder.name);
  1468.             break;
  1469.         case R.id.refresh_folder:
  1470.             checkMail(folder);
  1471.             break;
  1472.         case R.id.folder_settings:
  1473.             FolderSettings.actionSettings(this, mAccount, folder.name);
  1474.             break;
  1475.         case R.id.delete_account:
  1476.             onDeleteAccount(realAccount);
  1477.  
  1478.             break;
  1479.         case R.id.account_settings:
  1480.             onEditAccount();
  1481.  
  1482.             break;
  1483.         case R.id.activate:
  1484.             onActivateAccount(realAccount);
  1485.  
  1486.             break;
  1487.         case R.id.clear_pending:
  1488.             onClearCommands(realAccount);
  1489.  
  1490.             break;
  1491.         case R.id.empty_trash:
  1492.             onEmptyTrash(realAccount);
  1493.  
  1494.             break;
  1495.         case R.id.clear:
  1496.             onClear(realAccount);
  1497.  
  1498.             break;
  1499.         case R.id.recreate:
  1500.             onRecreate(realAccount);
  1501.  
  1502.             break;
  1503.         case R.id.export:
  1504.             onExport(false, realAccount);
  1505.  
  1506.             break;
  1507.         case R.id.move_up:
  1508.             onMove(realAccount, true);
  1509.  
  1510.             break;
  1511.         case R.id.move_down:
  1512.             onMove(realAccount, false);
  1513.  
  1514.             break;
  1515.         }
  1516.  
  1517.         return super.onContextItemSelected(item);
  1518.  
  1519.     }
  1520.  
  1521.     public void onDeleteAccount(Account account) {
  1522.         BaseAccount mSelectedContextAccount1 = account;
  1523.  
  1524.         showDialog(DIALOG_REMOVE_ACCOUNT);
  1525.     }
  1526.  
  1527.     void onEditAccount(Account account) {
  1528.         AccountSettings.actionSettings(this, mAccount);
  1529.     }
  1530.  
  1531.     @Override
  1532.     public Dialog onCreateDialog(int id) {
  1533.         // Android recreates our dialogs on configuration changes even when they
  1534.         // have been
  1535.         // dismissed. Make sure we have all information necessary before
  1536.         // creating a new dialog.
  1537.         switch (id) {
  1538.         case DIALOG_REMOVE_ACCOUNT: {
  1539.             if (mSelectedContextAccount == null) {
  1540.  
  1541.                 System.out.println(mSelectedContextAccount);
  1542.  
  1543.                 Log.d("this is returning null", "yep :(");
  1544.  
  1545.                 return null;
  1546.             }
  1547.  
  1548.             return ConfirmationDialog.create(
  1549.                     this,
  1550.                     id,
  1551.                     R.string.account_delete_dlg_title,
  1552.                     getString(R.string.account_delete_dlg_instructions_fmt,
  1553.                             mSelectedContextAccount.getDescription()),
  1554.                     R.string.okay_action, R.string.cancel_action,
  1555.                     new Runnable() {
  1556.                         @Override
  1557.                         public void run() {
  1558.                             if (mSelectedContextAccount instanceof Account) {
  1559.                                 Account realAccount = (Account) mSelectedContextAccount;
  1560.                                 try {
  1561.                                     realAccount.getLocalStore().delete();
  1562.                                 } catch (Exception e) {
  1563.                                     // Ignore, this may lead to localStores on
  1564.                                     // sd-cards that
  1565.                                     // are currently not inserted to be left
  1566.                                 }
  1567.                                 MessagingController.getInstance(
  1568.                                         getApplication()).notifyAccountCancel(
  1569.                                         MessageList.this, realAccount);
  1570.                                 Preferences.getPreferences(MessageList.this)
  1571.                                         .deleteAccount(realAccount);
  1572.                                 K9.setServicesEnabled(MessageList.this);
  1573.  
  1574.                             }
  1575.                         }
  1576.                     });
  1577.         }
  1578.         case DIALOG_CLEAR_ACCOUNT: {
  1579.             if (mSelectedContextAccount == null) {
  1580.  
  1581.                 Log.d("this is returning null", "yep :(");
  1582.                 return null;
  1583.             }
  1584.  
  1585.             return ConfirmationDialog.create(
  1586.                     this,
  1587.                     id,
  1588.                     R.string.account_clear_dlg_title,
  1589.                     getString(R.string.account_clear_dlg_instructions_fmt,
  1590.                             mSelectedContextAccount.getDescription()),
  1591.                     R.string.okay_action, R.string.cancel_action,
  1592.                     new Runnable() {
  1593.                         @Override
  1594.                         public void run() {
  1595.                             if (mSelectedContextAccount instanceof Account) {
  1596.                                 Account realAccount = (Account) mSelectedContextAccount;
  1597.                                 mHandler.workingAccount(R.string.clearing_account);
  1598.                                 MessagingController.getInstance(
  1599.                                         getApplication()).clear(realAccount,
  1600.                                         null);
  1601.                             }
  1602.                         }
  1603.                     });
  1604.         }
  1605.         case DIALOG_RECREATE_ACCOUNT: {
  1606.             if (mSelectedContextAccount == null) {
  1607.  
  1608.                 Log.d("this is returning null", "yep :(");
  1609.  
  1610.                 return null;
  1611.             }
  1612.  
  1613.             return ConfirmationDialog.create(
  1614.                     this,
  1615.                     id,
  1616.                     R.string.account_recreate_dlg_title,
  1617.                     getString(R.string.account_recreate_dlg_instructions_fmt,
  1618.                             mSelectedContextAccount.getDescription()),
  1619.                     R.string.okay_action, R.string.cancel_action,
  1620.                     new Runnable() {
  1621.                         @Override
  1622.                         public void run() {
  1623.                             if (mSelectedContextAccount instanceof Account) {
  1624.                                 Account realAccount = (Account) mSelectedContextAccount;
  1625.                                 mHandler.workingAccount(R.string.recreating_account);
  1626.                                 MessagingController.getInstance(
  1627.                                         getApplication()).recreate(realAccount,
  1628.                                         null);
  1629.                             }
  1630.                         }
  1631.                     });
  1632.         }
  1633.         case DIALOG_NO_FILE_MANAGER: {
  1634.             return ConfirmationDialog.create(this, id,
  1635.                     R.string.import_dialog_error_title,
  1636.                     getString(R.string.import_dialog_error_message),
  1637.                     R.string.open_market, R.string.close, new Runnable() {
  1638.                         @Override
  1639.                         public void run() {
  1640.                             Uri uri = Uri.parse(ANDROID_MARKET_URL);
  1641.                             Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  1642.                             startActivity(intent);
  1643.                         }
  1644.                     });
  1645.         }
  1646.         }
  1647.  
  1648.         return super.onCreateDialog(id);
  1649.     }
  1650.  
  1651.     @Override
  1652.     public void onPrepareDialog(int id, Dialog d) {
  1653.         AlertDialog alert = (AlertDialog) d;
  1654.         switch (id) {
  1655.         case DIALOG_REMOVE_ACCOUNT: {
  1656.             alert.setMessage(getString(
  1657.                     R.string.account_delete_dlg_instructions_fmt,
  1658.                     mSelectedContextAccount.getDescription()));
  1659.             break;
  1660.         }
  1661.         case DIALOG_CLEAR_ACCOUNT: {
  1662.             alert.setMessage(getString(
  1663.                     R.string.account_clear_dlg_instructions_fmt,
  1664.                     mSelectedContextAccount.getDescription()));
  1665.             break;
  1666.         }
  1667.         case DIALOG_RECREATE_ACCOUNT: {
  1668.             alert.setMessage(getString(
  1669.                     R.string.account_recreate_dlg_instructions_fmt,
  1670.                     mSelectedContextAccount.getDescription()));
  1671.             break;
  1672.         }
  1673.         }
  1674.  
  1675.         super.onPrepareDialog(id, d);
  1676.     }
  1677.  
  1678.     void onClear(Account account) {
  1679.         showDialog(DIALOG_CLEAR_ACCOUNT);
  1680.  
  1681.     }
  1682.  
  1683.     void onRecreate(Account account) {
  1684.         showDialog(DIALOG_RECREATE_ACCOUNT);
  1685.     }
  1686.  
  1687.     class FolderListAdapter extends BaseAdapter implements Filterable {
  1688.         private ArrayList<FolderInfoHolder> mFolders = new ArrayList<FolderInfoHolder>();
  1689.         private List<FolderInfoHolder> mFilteredFolders = Collections
  1690.                 .unmodifiableList(mFolders);
  1691.         private Filter mFilter = new FolderListFilter();
  1692.  
  1693.         public Object getItem(long position) {
  1694.             return getItem((int) position);
  1695.         }
  1696.  
  1697.         @Override
  1698.         public Object getItem(int position) {
  1699.             return mFilteredFolders.get(position);
  1700.         }
  1701.  
  1702.         @Override
  1703.         public long getItemId(int position) {
  1704.             return mFilteredFolders.get(position).folder.getName().hashCode();
  1705.         }
  1706.  
  1707.         @Override
  1708.         public int getCount() {
  1709.             return mFilteredFolders.size();
  1710.         }
  1711.  
  1712.         @Override
  1713.         public boolean isEnabled(int item) {
  1714.             return true;
  1715.         }
  1716.  
  1717.         @Override
  1718.         public boolean areAllItemsEnabled() {
  1719.             return true;
  1720.         }
  1721.  
  1722.         private ActivityListener mListener = new ActivityListener() {
  1723.             @Override
  1724.             public void informUserOfStatus() {
  1725.  
  1726.                 mHandler.dataChanged();
  1727.             }
  1728.  
  1729.             @Override
  1730.             public void accountStatusChanged(BaseAccount account,
  1731.                     AccountStats stats) {
  1732.                 if (!account.equals(mAccount)) {
  1733.                     return;
  1734.                 }
  1735.                 if (stats == null) {
  1736.                     return;
  1737.                 }
  1738.                 mUnreadMessageCount = stats.unreadMessageCount;
  1739.  
  1740.                 System.out.println("1 Unread Messages= " + mUnreadMessageCount);
  1741.  
  1742.             }
  1743.  
  1744.             @Override
  1745.             public void listFoldersStarted(Account account) {
  1746.                 if (account.equals(mAccount)) {
  1747.                     mHandler.progress(true);
  1748.                 }
  1749.                 super.listFoldersStarted(account);
  1750.  
  1751.             }
  1752.  
  1753.             @Override
  1754.             public void listFoldersFailed(Account account, String message) {
  1755.                 if (account.equals(mAccount)) {
  1756.  
  1757.                     mHandler.progress(false);
  1758.                 }
  1759.                 super.listFoldersFailed(account, message);
  1760.             }
  1761.  
  1762.             @Override
  1763.             public void listFoldersFinished(Account account) {
  1764.                 if (account.equals(mAccount)) {
  1765.  
  1766.                     mHandler.progress(false);
  1767.                     MessagingController.getInstance(getApplication())
  1768.                             .refreshListener(mAdapter.mListener);
  1769.                     mHandler.dataChanged();
  1770.                 }
  1771.                 super.listFoldersFinished(account);
  1772.  
  1773.             }
  1774.  
  1775.             @Override
  1776.             public void listFolders(Account account, Folder[] folders) {
  1777.                 if (account.equals(mAccount)) {
  1778.  
  1779.                     List<FolderInfoHolder> newFolders = new LinkedList<FolderInfoHolder>();
  1780.                     List<FolderInfoHolder> topFolders = new LinkedList<FolderInfoHolder>();
  1781.  
  1782.                     Account.FolderMode aMode = account.getFolderDisplayMode();
  1783.                     Preferences prefs = Preferences
  1784.                             .getPreferences(getApplication()
  1785.                                     .getApplicationContext());
  1786.                     for (Folder folder : folders) {
  1787.                         try {
  1788.                             folder.refresh(prefs);
  1789.  
  1790.                             Folder.FolderClass fMode = folder.getDisplayClass();
  1791.  
  1792.                             if ((aMode == Account.FolderMode.FIRST_CLASS && fMode != Folder.FolderClass.FIRST_CLASS)
  1793.                                     || (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS
  1794.                                             && fMode != Folder.FolderClass.FIRST_CLASS && fMode != Folder.FolderClass.SECOND_CLASS)
  1795.                                     || (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS)) {
  1796.                                 continue;
  1797.                             }
  1798.                         } catch (MessagingException me) {
  1799.                             Log.e(K9.LOG_TAG,
  1800.                                     "Couldn't get prefs to check for displayability of folder "
  1801.                                             + folder.getName(), me);
  1802.                         }
  1803.  
  1804.                         FolderInfoHolder holder = null;
  1805.  
  1806.                         int folderIndex = getFolderIndex(folder.getName());
  1807.                         if (folderIndex >= 0) {
  1808.                             holder = (FolderInfoHolder) getItem(folderIndex);
  1809.                         }
  1810.  
  1811.                         if (holder == null) {
  1812.                             holder = new FolderInfoHolder(context, folder,
  1813.                                     mAccount, -1);
  1814.                         } else {
  1815.                             holder.populate(context, folder, mAccount, -1);
  1816.  
  1817.                         }
  1818.                         if (folder.isInTopGroup()) {
  1819.                             topFolders.add(holder);
  1820.                         } else {
  1821.                             newFolders.add(holder);
  1822.                         }
  1823.                     }
  1824.                     Collections.sort(newFolders);
  1825.                     Collections.sort(topFolders);
  1826.                     topFolders.addAll(newFolders);
  1827.                     mHandler.newFolders(topFolders);
  1828.                 }
  1829.                 super.listFolders(account, folders);
  1830.             }
  1831.  
  1832.             @Override
  1833.             public void synchronizeMailboxStarted(Account account, String folder) {
  1834.                 super.synchronizeMailboxStarted(account, folder);
  1835.                 if (account.equals(mAccount)) {
  1836.  
  1837.                     mHandler.progress(true);
  1838.                     mHandler.folderLoading(folder, true);
  1839.                     mHandler.dataChanged();
  1840.                 }
  1841.  
  1842.             }
  1843.  
  1844.             @Override
  1845.             public void synchronizeMailboxFinished(Account account,
  1846.                     String folder, int totalMessagesInMailbox,
  1847.                     int numNewMessages) {
  1848.                 super.synchronizeMailboxFinished(account, folder,
  1849.                         totalMessagesInMailbox, numNewMessages);
  1850.                 if (account.equals(mAccount)) {
  1851.                     mHandler.progress(false);
  1852.                     mHandler.folderLoading(folder, false);
  1853.  
  1854.                     refreshFolder(account, folder);
  1855.                 }
  1856.  
  1857.             }
  1858.  
  1859.             private void refreshFolder(Account account, String folderName) {
  1860.                 // There has to be a cheaper way to get at the localFolder
  1861.                 // object than this
  1862.                 Folder localFolder = null;
  1863.                 try {
  1864.                     if (account != null && folderName != null) {
  1865.                         if (!account.isAvailable(MessageList.this)) {
  1866.                             Log.i(K9.LOG_TAG,
  1867.                                     "not refreshing folder of unavailable account");
  1868.                             return;
  1869.                         }
  1870.                         localFolder = account.getLocalStore().getFolder(
  1871.                                 folderName);
  1872.                         FolderInfoHolder folderHolder = getFolder(folderName);
  1873.                         if (folderHolder != null) {
  1874.                             folderHolder.populate(context, localFolder,
  1875.                                     mAccount, -1);
  1876.                             folderHolder.flaggedMessageCount = -1;
  1877.  
  1878.                             mHandler.dataChanged();
  1879.                         }
  1880.                     }
  1881.                 } catch (Exception e) {
  1882.                     Log.e(K9.LOG_TAG, "Exception while populating folder", e);
  1883.                 } finally {
  1884.                     if (localFolder != null) {
  1885.                         localFolder.close();
  1886.                     }
  1887.                 }
  1888.  
  1889.             }
  1890.  
  1891.             @Override
  1892.             public void synchronizeMailboxFailed(Account account,
  1893.                     String folder, String message) {
  1894.                 super.synchronizeMailboxFailed(account, folder, message);
  1895.                 if (!account.equals(mAccount)) {
  1896.                     return;
  1897.                 }
  1898.  
  1899.                 mHandler.progress(false);
  1900.  
  1901.                 mHandler.folderLoading(folder, false);
  1902.  
  1903.                 // String mess = truncateStatus(message);
  1904.  
  1905.                 // mHandler.folderStatus(folder, mess);
  1906.                 FolderInfoHolder holder = getFolder(folder);
  1907.  
  1908.                 if (holder != null) {
  1909.                     holder.lastChecked = 0;
  1910.                 }
  1911.  
  1912.                 mHandler.dataChanged();
  1913.  
  1914.             }
  1915.  
  1916.             @Override
  1917.             public void setPushActive(Account account, String folderName,
  1918.                     boolean enabled) {
  1919.                 if (!account.equals(mAccount)) {
  1920.                     return;
  1921.                 }
  1922.                 FolderInfoHolder holder = getFolder(folderName);
  1923.  
  1924.                 if (holder != null) {
  1925.                     holder.pushActive = enabled;
  1926.  
  1927.                     mHandler.dataChanged();
  1928.                 }
  1929.             }
  1930.  
  1931.             @Override
  1932.             public void messageDeleted(Account account, String folder,
  1933.                     Message message) {
  1934.                 synchronizeMailboxRemovedMessage(account, folder, message);
  1935.             }
  1936.  
  1937.             @Override
  1938.             public void emptyTrashCompleted(Account account) {
  1939.                 if (account.equals(mAccount)) {
  1940.                     refreshFolder(account, mAccount.getTrashFolderName());
  1941.                 }
  1942.             }
  1943.  
  1944.             @Override
  1945.             public void folderStatusChanged(Account account, String folderName,
  1946.                     int unreadMessageCount) {
  1947.                 if (account.equals(mAccount)) {
  1948.                     refreshFolder(account, folderName);
  1949.                     informUserOfStatus();
  1950.                 }
  1951.             }
  1952.  
  1953.             @Override
  1954.             public void sendPendingMessagesCompleted(Account account) {
  1955.                 super.sendPendingMessagesCompleted(account);
  1956.                 if (account.equals(mAccount)) {
  1957.                     refreshFolder(account, mAccount.getOutboxFolderName());
  1958.                 }
  1959.             }
  1960.  
  1961.             @Override
  1962.             public void sendPendingMessagesStarted(Account account) {
  1963.                 super.sendPendingMessagesStarted(account);
  1964.  
  1965.                 if (account.equals(mAccount)) {
  1966.                     mHandler.dataChanged();
  1967.                 }
  1968.             }
  1969.  
  1970.             @Override
  1971.             public void sendPendingMessagesFailed(Account account) {
  1972.                 super.sendPendingMessagesFailed(account);
  1973.                 if (account.equals(mAccount)) {
  1974.                     refreshFolder(account, mAccount.getOutboxFolderName());
  1975.                 }
  1976.             }
  1977.  
  1978.             @Override
  1979.             public void accountSizeChanged(Account account, long oldSize,
  1980.                     long newSize) {
  1981.                 if (account.equals(mAccount)) {
  1982.                     mHandler.accountSizeChanged(oldSize, newSize);
  1983.                 }
  1984.             }
  1985.         };
  1986.  
  1987.         public int getFolderIndex(String folder) {
  1988.             FolderInfoHolder searchHolder = new FolderInfoHolder();
  1989.             searchHolder.name = folder;
  1990.             return mFilteredFolders.indexOf(searchHolder);
  1991.         }
  1992.  
  1993.         public FolderInfoHolder getFolder(String folder) {
  1994.             FolderInfoHolder holder = null;
  1995.  
  1996.             int index = getFolderIndex(folder);
  1997.             if (index >= 0) {
  1998.                 holder = (FolderInfoHolder) getItem(index);
  1999.                 if (holder != null) {
  2000.                     return holder;
  2001.                 }
  2002.             }
  2003.             return null;
  2004.         }
  2005.  
  2006.         @Override
  2007.         public View getView(int position, View convertView, ViewGroup parent) {
  2008.             if (position <= getCount()) {
  2009.                 return getItemView(position, convertView, parent);
  2010.             } else {
  2011.                 Log.e(K9.LOG_TAG, "getView with illegal positon=" + position
  2012.                         + " called! count is only " + getCount());
  2013.                 return null;
  2014.             }
  2015.         }
  2016.  
  2017.         public View getItemView(int itemPosition, View convertView,
  2018.                 ViewGroup parent) {
  2019.             FolderInfoHolder folder = (FolderInfoHolder) getItem(itemPosition);
  2020.             View view;
  2021.             if (convertView != null) {
  2022.                 view = convertView;
  2023.             } else {
  2024.                 view = mInflater.inflate(R.layout.folder_list_item, parent,
  2025.                         false);
  2026.             }
  2027.  
  2028.             FolderViewHolder holder = (FolderViewHolder) view.getTag();
  2029.  
  2030.             if (holder == null) {
  2031.                 holder = new FolderViewHolder();
  2032.                 holder.folderName = (TextView) view
  2033.                         .findViewById(R.id.folder_name);
  2034.                 holder.newMessageCount = (TextView) view
  2035.                         .findViewById(R.id.new_message_count);
  2036.                 holder.flaggedMessageCount = (TextView) view
  2037.                         .findViewById(R.id.flagged_message_count);
  2038.                 holder.newMessageCountWrapper = view
  2039.                         .findViewById(R.id.new_message_count_wrapper);
  2040.                 holder.flaggedMessageCountWrapper = view
  2041.                         .findViewById(R.id.flagged_message_count_wrapper);
  2042.                 holder.newMessageCountIcon = view
  2043.                         .findViewById(R.id.new_message_count_icon);
  2044.                 holder.flaggedMessageCountIcon = view
  2045.                         .findViewById(R.id.flagged_message_count_icon);
  2046.                 holder.chip = view.findViewById(R.id.chip);
  2047.                 holder.folderStatus = (TextView) view
  2048.                         .findViewById(R.id.folder_status);
  2049.                 holder.activeIcons = (RelativeLayout) view
  2050.                         .findViewById(R.id.active_icons);
  2051.  
  2052.                 holder.folderListItemLayout = (LinearLayout) view
  2053.                         .findViewById(R.id.folder_list_item_layout);
  2054.                 holder.rawFolderName = folder.name;
  2055.  
  2056.                 view.setTag(holder);
  2057.             }
  2058.  
  2059.             if (folder == null) {
  2060.                 return view;
  2061.             }
  2062.  
  2063.             final String folderStatus;
  2064.  
  2065.             if (folder.loading) {
  2066.                 folderStatus = getString(R.string.status_loading);
  2067.             } else if (folder.status != null) {
  2068.                 folderStatus = folder.status;
  2069.             } else if (folder.lastChecked != 0) {
  2070.                 long now = System.currentTimeMillis();
  2071.                 int flags = DateUtils.FORMAT_SHOW_TIME
  2072.                         | DateUtils.FORMAT_SHOW_DATE
  2073.                         | DateUtils.FORMAT_SHOW_YEAR;
  2074.                 CharSequence formattedDate;
  2075.  
  2076.                 if (Math.abs(now - folder.lastChecked) > DateUtils.WEEK_IN_MILLIS) {
  2077.                     formattedDate = getString(R.string.preposition_for_date,
  2078.                             DateUtils.formatDateTime(context,
  2079.                                     folder.lastChecked, flags));
  2080.                 } else {
  2081.                     formattedDate = DateUtils.getRelativeTimeSpanString(
  2082.                             folder.lastChecked, now,
  2083.                             DateUtils.MINUTE_IN_MILLIS, flags);
  2084.                 }
  2085.  
  2086.                 folderStatus = getString(
  2087.                         folder.pushActive ? R.string.last_refresh_time_format_with_push
  2088.                                 : R.string.last_refresh_time_format,
  2089.                         formattedDate);
  2090.             } else {
  2091.                 folderStatus = null;
  2092.             }
  2093.  
  2094.             holder.folderName.setText(folder.displayName);
  2095.             Log.d("Folder Unread = ", folder.displayName);
  2096.  
  2097.             if (folderStatus != null) {
  2098.                 holder.folderStatus.setText(folderStatus);
  2099.                 holder.folderStatus.setVisibility(View.VISIBLE);
  2100.             } else {
  2101.                 holder.folderStatus.setVisibility(View.GONE);
  2102.             }
  2103.  
  2104.             if (folder.unreadMessageCount == -1) {
  2105.                 folder.unreadMessageCount = 0;
  2106.                 try {
  2107.                     folder.unreadMessageCount = folder.folder
  2108.                             .getUnreadMessageCount();
  2109.  
  2110.                 } catch (Exception e) {
  2111.                     Log.e(K9.LOG_TAG, "Unable to get unreadMessageCount for "
  2112.                             + mAccount.getDescription() + ":" + folder.name);
  2113.                 }
  2114.             }
  2115.             if (folder.unreadMessageCount > 0) {
  2116.                 holder.newMessageCount.setText(Integer
  2117.                         .toString(folder.unreadMessageCount));
  2118.  
  2119.                 holder.newMessageCountWrapper
  2120.                         .setOnClickListener(createUnreadSearch(mAccount, folder));
  2121.                 holder.newMessageCountWrapper.setVisibility(View.VISIBLE);
  2122.  
  2123.             } else {
  2124.                 holder.newMessageCountWrapper.setVisibility(View.GONE);
  2125.             }
  2126.  
  2127.             if (folder.flaggedMessageCount == -1) {
  2128.                 folder.flaggedMessageCount = 0;
  2129.                 try {
  2130.                     folder.flaggedMessageCount = folder.folder
  2131.                             .getFlaggedMessageCount();
  2132.                 } catch (Exception e) {
  2133.                     Log.e(K9.LOG_TAG, "Unable to get flaggedMessageCount for "
  2134.                             + mAccount.getDescription() + ":" + folder.name);
  2135.                 }
  2136.  
  2137.             }
  2138.  
  2139.             if (K9.messageListStars() && folder.flaggedMessageCount > 0) {
  2140.                 holder.flaggedMessageCount.setText(Integer
  2141.                         .toString(folder.flaggedMessageCount));
  2142.                 holder.flaggedMessageCountWrapper
  2143.                         .setOnClickListener(createFlaggedSearch(mAccount,
  2144.                                 folder));
  2145.                 holder.flaggedMessageCountWrapper.setVisibility(View.VISIBLE);
  2146.  
  2147.             } else {
  2148.                 holder.flaggedMessageCountWrapper.setVisibility(View.GONE);
  2149.             }
  2150.  
  2151.             holder.activeIcons.setOnClickListener(new OnClickListener() {
  2152.                 @Override
  2153.                 public void onClick(View v) {
  2154.                     Toast toast = Toast.makeText(getApplication(),
  2155.                             getString(R.string.tap_hint), Toast.LENGTH_SHORT);
  2156.                     toast.show();
  2157.                 }
  2158.             });
  2159.  
  2160.             holder.chip.setBackgroundColor(mAccount.getChipColor());
  2161.  
  2162.             mFontSizes.setViewTextSize(holder.folderName,
  2163.                     mFontSizes.getFolderName());
  2164.  
  2165.             if (K9.wrapFolderNames()) {
  2166.                 holder.folderName.setEllipsize(null);
  2167.                 holder.folderName.setSingleLine(false);
  2168.             } else {
  2169.                 holder.folderName.setEllipsize(TruncateAt.START);
  2170.                 holder.folderName.setSingleLine(true);
  2171.             }
  2172.             mFontSizes.setViewTextSize(holder.folderStatus,
  2173.                     mFontSizes.getFolderStatus());
  2174.  
  2175.             return view;
  2176.         }
  2177.  
  2178.         private OnClickListener createFlaggedSearch(Account account,
  2179.                 FolderInfoHolder folder) {
  2180.             Log.d("clicked_folder6", "clicked");
  2181.  
  2182.             String searchTitle = getString(
  2183.                     R.string.search_title,
  2184.                     getString(R.string.message_list_title,
  2185.                             account.getDescription(), folder.displayName),
  2186.                     getString(R.string.flagged_modifier));
  2187.  
  2188.             LocalSearch search = new LocalSearch(searchTitle);
  2189.             search.and(Searchfield.FLAGGED, "1", Attribute.EQUALS);
  2190.  
  2191.             search.addAllowedFolder(folder.name);
  2192.             search.addAccountUuid(account.getUuid());
  2193.  
  2194.             return new FolderClickListener(search);
  2195.         }
  2196.  
  2197.         private OnClickListener createUnreadSearch(Account mAccount,
  2198.                 FolderInfoHolder folder) {
  2199.             Log.d("clicked_folder7", "clicked");
  2200.             String searchTitle = getString(
  2201.                     R.string.search_title,
  2202.                     getString(R.string.message_list_title,
  2203.                             ((BaseAccount) mAccount).getDescription(),
  2204.                             folder.displayName),
  2205.                     getString(R.string.unread_modifier));
  2206.  
  2207.             LocalSearch search = new LocalSearch(searchTitle);
  2208.             search.and(Searchfield.READ, "1", Attribute.NOT_EQUALS);
  2209.  
  2210.             search.addAllowedFolder(folder.name);
  2211.             search.addAccountUuid(((BaseAccount) mAccount).getUuid());
  2212.  
  2213.             return new FolderClickListener(search);
  2214.         }
  2215.  
  2216.         @Override
  2217.         public boolean hasStableIds() {
  2218.             return true;
  2219.         }
  2220.  
  2221.         public boolean isItemSelectable(int position) {
  2222.             return true;
  2223.         }
  2224.  
  2225.         public void setFilter(final Filter filter) {
  2226.             this.mFilter = filter;
  2227.         }
  2228.  
  2229.         @Override
  2230.         public Filter getFilter() {
  2231.             return mFilter;
  2232.         }
  2233.  
  2234.         /**
  2235.          * Filter to search for occurences of the search-expression in any place
  2236.          * of the folder-name instead of doing jsut a prefix-search.
  2237.          *
  2238.          * @author Marcus@Wolschon.biz
  2239.          */
  2240.         public class FolderListFilter extends Filter {
  2241.             private CharSequence mSearchTerm;
  2242.  
  2243.             public CharSequence getSearchTerm() {
  2244.                 return mSearchTerm;
  2245.             }
  2246.  
  2247.             /**
  2248.              * Do the actual search. {@inheritDoc}
  2249.              *
  2250.              * @see #publishResults(CharSequence, FilterResults)
  2251.              */
  2252.             @Override
  2253.             protected FilterResults performFiltering(CharSequence searchTerm) {
  2254.                 mSearchTerm = searchTerm;
  2255.                 FilterResults results = new FilterResults();
  2256.  
  2257.                 Locale locale = Locale.getDefault();
  2258.                 if ((searchTerm == null) || (searchTerm.length() == 0)) {
  2259.                     ArrayList<FolderInfoHolder> list = new ArrayList<FolderInfoHolder>(
  2260.                             mFolders);
  2261.                     results.values = list;
  2262.                     results.count = list.size();
  2263.                 } else {
  2264.                     final String searchTermString = searchTerm.toString()
  2265.                             .toLowerCase(locale);
  2266.                     final String[] words = searchTermString.split(" ");
  2267.                     final int wordCount = words.length;
  2268.  
  2269.                     final ArrayList<FolderInfoHolder> newValues = new ArrayList<FolderInfoHolder>();
  2270.  
  2271.                     for (final FolderInfoHolder value : mFolders) {
  2272.                         if (value.displayName == null) {
  2273.                             continue;
  2274.                         }
  2275.                         final String valueText = value.displayName
  2276.                                 .toLowerCase(locale);
  2277.  
  2278.                         for (int k = 0; k < wordCount; k++) {
  2279.                             if (valueText.contains(words[k])) {
  2280.                                 newValues.add(value);
  2281.                                 break;
  2282.                             }
  2283.                         }
  2284.                     }
  2285.  
  2286.                     results.values = newValues;
  2287.                     results.count = newValues.size();
  2288.                 }
  2289.  
  2290.                 return results;
  2291.             }
  2292.  
  2293.             /**
  2294.              * Publish the results to the user-interface. {@inheritDoc}
  2295.              */
  2296.             @SuppressWarnings("unchecked")
  2297.             @Override
  2298.             protected void publishResults(CharSequence constraint,
  2299.                     FilterResults results) {
  2300.                 // noinspection unchecked
  2301.                 mFilteredFolders = Collections
  2302.                         .unmodifiableList((ArrayList<FolderInfoHolder>) results.values);
  2303.                 // Send notification that the data set changed now
  2304.                 notifyDataSetChanged();
  2305.             }
  2306.         }
  2307.     }
  2308.  
  2309.     static class FolderViewHolder {
  2310.         public TextView folderName;
  2311.  
  2312.         public TextView folderStatus;
  2313.  
  2314.         public TextView newMessageCount;
  2315.         public TextView flaggedMessageCount;
  2316.         public View newMessageCountIcon;
  2317.         public View flaggedMessageCountIcon;
  2318.         public View newMessageCountWrapper;
  2319.         public View flaggedMessageCountWrapper;
  2320.         public View chip;
  2321.         public RelativeLayout activeIcons;
  2322.         public String rawFolderName;
  2323.  
  2324.         public LinearLayout folderListItemLayout;
  2325.     }
  2326.  
  2327.     private class FolderClickListener implements OnClickListener {
  2328.  
  2329.         final LocalSearch search;
  2330.  
  2331.         FolderClickListener(LocalSearch search) {
  2332.             this.search = search;
  2333.         }
  2334.  
  2335.         @Override
  2336.         public void onClick(View v) {
  2337.             MessageList.actionDisplaySearch(MessageList.this, search, true,
  2338.                     false);
  2339.  
  2340.             Log.d("clicked_folder8", "clicked");
  2341.         }
  2342.     }
  2343.  
  2344.     /**
  2345.      * Get references to existing fragments if the activity was restarted.
  2346.      */
  2347.     private void findFragments() {
  2348.         FragmentManager fragmentManager = getFragmentManager();
  2349.         mMessageListFragment = (MessageListFragment) fragmentManager
  2350.                 .findFragmentById(R.id.message_list_container);
  2351.         mMessageViewFragment = (MessageViewFragment) fragmentManager
  2352.                 .findFragmentById(R.id.message_view_container);
  2353.     }
  2354.  
  2355.     /**
  2356.      * Create fragment instances if necessary.
  2357.      *
  2358.      * @see #findFragments()
  2359.      */
  2360.  
  2361.     private void removeFragments() {
  2362.         FragmentManager fragmentManager = getFragmentManager();
  2363.         fragmentManager.addOnBackStackChangedListener(this);
  2364.  
  2365.         boolean hasMessageListFragment = (mMessageListFragment != null);
  2366.  
  2367.         if (!hasMessageListFragment) {
  2368.             FragmentTransaction ft = fragmentManager.beginTransaction();
  2369.             mMessageListFragment = MessageListFragment.newInstance(mSearch,
  2370.                     false, (K9.isThreadedViewEnabled() && !mNoThreading));
  2371.             ft.remove(mMessageListFragment);
  2372.             ft.commit();
  2373.  
  2374.             Log.d("removed fragment?", "yes");
  2375.         }
  2376.  
  2377.         // Check if the fragment wasn't restarted and has a MessageReference in
  2378.         // the arguments. If
  2379.         // so, open the referenced message.
  2380.         if (!hasMessageListFragment && mMessageViewFragment == null
  2381.                 && mMessageReference != null) {
  2382.             openMessage(mMessageReference);
  2383.         }
  2384.     }
  2385.  
  2386.     private void initializeFragments() {
  2387.         FragmentManager fragmentManager = getFragmentManager();
  2388.         fragmentManager.addOnBackStackChangedListener(this);
  2389.  
  2390.         boolean hasMessageListFragment = (mMessageListFragment != null);
  2391.  
  2392.         if (!hasMessageListFragment) {
  2393.             FragmentTransaction ft = fragmentManager.beginTransaction();
  2394.             mMessageListFragment = MessageListFragment.newInstance(mSearch,
  2395.                     false, (K9.isThreadedViewEnabled() && !mNoThreading));
  2396.             ft.add(R.id.message_list_container, mMessageListFragment);
  2397.             ft.commit();
  2398.         }
  2399.  
  2400.         // Check if the fragment wasn't restarted and has a MessageReference in
  2401.         // the arguments. If
  2402.         // so, open the referenced message.
  2403.         if (!hasMessageListFragment && mMessageViewFragment == null
  2404.                 && mMessageReference != null) {
  2405.             openMessage(mMessageReference);
  2406.         }
  2407.     }
  2408.  
  2409.     /**
  2410.      * Set the initial display mode (message list, message view, or split view).
  2411.      *
  2412.      * <p>
  2413.      * <strong>Note:</strong> This method has to be called after
  2414.      * {@link #findFragments()} because the result depends on the availability
  2415.      * of a {@link MessageViewFragment} instance.
  2416.      * </p>
  2417.      *
  2418.      * @param savedInstanceState
  2419.      *            The saved instance state that was passed to the activity as
  2420.      *            argument to {@link #onCreate(Bundle)}. May be {@code null}.
  2421.      */
  2422.     private void initializeDisplayMode(Bundle savedInstanceState) {
  2423.         if (useSplitView()) {
  2424.             mDisplayMode = DisplayMode.SPLIT_VIEW;
  2425.             return;
  2426.         }
  2427.  
  2428.         if (savedInstanceState != null) {
  2429.             DisplayMode savedDisplayMode = (DisplayMode) savedInstanceState
  2430.                     .getSerializable(STATE_DISPLAY_MODE);
  2431.             if (savedDisplayMode != DisplayMode.SPLIT_VIEW) {
  2432.                 mDisplayMode = savedDisplayMode;
  2433.                 return;
  2434.             }
  2435.         }
  2436.  
  2437.         if (mMessageViewFragment != null || mMessageReference != null) {
  2438.             mDisplayMode = DisplayMode.MESSAGE_VIEW;
  2439.         } else {
  2440.             mDisplayMode = DisplayMode.MESSAGE_LIST;
  2441.         }
  2442.     }
  2443.  
  2444.     private boolean useSplitView() {
  2445.         SplitViewMode splitViewMode = K9.getSplitViewMode();
  2446.         int orientation = getResources().getConfiguration().orientation;
  2447.  
  2448.         return (splitViewMode == SplitViewMode.ALWAYS || (splitViewMode == SplitViewMode.WHEN_IN_LANDSCAPE && orientation == Configuration.ORIENTATION_LANDSCAPE));
  2449.     }
  2450.  
  2451.     private void initializeLayout() {
  2452.         mMessageViewContainer = (ViewGroup) findViewById(R.id.message_view_container);
  2453.         mMessageViewPlaceHolder = getLayoutInflater().inflate(
  2454.                 R.layout.empty_message_view, null);
  2455.     }
  2456.  
  2457.     private void displayViews() {
  2458.         switch (mDisplayMode) {
  2459.         case MESSAGE_LIST: {
  2460.             showMessageList();
  2461.             break;
  2462.         }
  2463.         case MESSAGE_VIEW: {
  2464.             showMessageView();
  2465.             break;
  2466.         }
  2467.         case SPLIT_VIEW: {
  2468.             mMessageListWasDisplayed = true;
  2469.             if (mMessageViewFragment == null) {
  2470.                 showMessageViewPlaceHolder();
  2471.             } else {
  2472.                 MessageReference activeMessage = mMessageViewFragment
  2473.                         .getMessageReference();
  2474.                 if (activeMessage != null) {
  2475.                     mMessageListFragment.setActiveMessage(activeMessage);
  2476.                 }
  2477.             }
  2478.             break;
  2479.         }
  2480.         }
  2481.     }
  2482.  
  2483.     private boolean decodeExtras(Intent intent) {
  2484.         String action = intent.getAction();
  2485.         if (Intent.ACTION_VIEW.equals(action) && intent.getData() != null) {
  2486.             Uri uri = intent.getData();
  2487.             List<String> segmentList = uri.getPathSegments();
  2488.  
  2489.             String accountId = segmentList.get(0);
  2490.             Collection<Account> accounts = Preferences.getPreferences(this)
  2491.                     .getAvailableAccounts();
  2492.             for (Account account : accounts) {
  2493.                 if (String.valueOf(account.getAccountNumber())
  2494.                         .equals(accountId)) {
  2495.                     mMessageReference = new MessageReference();
  2496.                     mMessageReference.accountUuid = account.getUuid();
  2497.                     mMessageReference.folderName = segmentList.get(1);
  2498.                     mMessageReference.uid = segmentList.get(2);
  2499.                     break;
  2500.                 }
  2501.             }
  2502.         } else if (ACTION_SHORTCUT.equals(action)) {
  2503.             // Handle shortcut intents
  2504.             String specialFolder = intent.getStringExtra(EXTRA_SPECIAL_FOLDER);
  2505.             if (SearchAccount.UNIFIED_INBOX.equals(specialFolder)) {
  2506.                 mSearch = SearchAccount.createUnifiedInboxAccount(this)
  2507.                         .getRelatedSearch();
  2508.             } else if (SearchAccount.ALL_MESSAGES.equals(specialFolder)) {
  2509.                 mSearch = SearchAccount.createAllMessagesAccount(this)
  2510.                         .getRelatedSearch();
  2511.             }
  2512.         } else if (intent.getStringExtra(SearchManager.QUERY) != null) {
  2513.             // check if this intent comes from the system search ( remote )
  2514.             if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
  2515.                 // Query was received from Search Dialog
  2516.                 String query = intent.getStringExtra(SearchManager.QUERY);
  2517.  
  2518.                 mSearch = new LocalSearch(getString(R.string.search_results));
  2519.                 mSearch.setManualSearch(true);
  2520.                 mNoThreading = true;
  2521.  
  2522.                 mSearch.or(new SearchCondition(Searchfield.SENDER,
  2523.                         Attribute.CONTAINS, query));
  2524.                 mSearch.or(new SearchCondition(Searchfield.SUBJECT,
  2525.                         Attribute.CONTAINS, query));
  2526.                 mSearch.or(new SearchCondition(Searchfield.MESSAGE_CONTENTS,
  2527.                         Attribute.CONTAINS, query));
  2528.  
  2529.                 Bundle appData = intent.getBundleExtra(SearchManager.APP_DATA);
  2530.                 if (appData != null) {
  2531.                     mSearch.addAccountUuid(appData
  2532.                             .getString(EXTRA_SEARCH_ACCOUNT));
  2533.                     // searches started from a folder list activity will provide
  2534.                     // an account, but no folder
  2535.                     if (appData.getString(EXTRA_SEARCH_FOLDER) != null) {
  2536.                         mSearch.addAllowedFolder(appData
  2537.                                 .getString(EXTRA_SEARCH_FOLDER));
  2538.                     }
  2539.                 } else {
  2540.                     mSearch.addAccountUuid(SearchSpecification.ALL_ACCOUNTS);
  2541.                 }
  2542.             }
  2543.         } else {
  2544.             // regular LocalSearch object was passed
  2545.             mSearch = intent.getParcelableExtra(EXTRA_SEARCH);
  2546.             mNoThreading = intent.getBooleanExtra(EXTRA_NO_THREADING, false);
  2547.         }
  2548.  
  2549.         if (mMessageReference == null) {
  2550.             mMessageReference = intent
  2551.                     .getParcelableExtra(EXTRA_MESSAGE_REFERENCE);
  2552.         }
  2553.  
  2554.         if (mMessageReference != null) {
  2555.             mSearch = new LocalSearch();
  2556.             mSearch.addAccountUuid(mMessageReference.accountUuid);
  2557.             mSearch.addAllowedFolder(mMessageReference.folderName);
  2558.         }
  2559.  
  2560.         if (mSearch == null) {
  2561.             // We've most likely been started by an old unread widget
  2562.             String accountUuid = intent.getStringExtra("account");
  2563.             String folderName = intent.getStringExtra("folder");
  2564.  
  2565.             mSearch = new LocalSearch(folderName);
  2566.             mSearch.addAccountUuid((accountUuid == null) ? "invalid"
  2567.                     : accountUuid);
  2568.             if (folderName != null) {
  2569.                 mSearch.addAllowedFolder(folderName);
  2570.             }
  2571.         }
  2572.  
  2573.         Preferences prefs = Preferences.getPreferences(getApplicationContext());
  2574.  
  2575.         String[] accountUuids = mSearch.getAccountUuids();
  2576.         if (mSearch.searchAllAccounts()) {
  2577.             Account[] accounts = prefs.getAccounts();
  2578.             mSingleAccountMode = (accounts.length == 1);
  2579.             if (mSingleAccountMode) {
  2580.                 mAccount = accounts[0];
  2581.             }
  2582.         } else {
  2583.             mSingleAccountMode = (accountUuids.length == 1);
  2584.             if (mSingleAccountMode) {
  2585.                 mAccount = prefs.getAccount(accountUuids[0]);
  2586.             }
  2587.         }
  2588.         mSingleFolderMode = mSingleAccountMode
  2589.                 && (mSearch.getFolderNames().size() == 1);
  2590.  
  2591.         if (mSingleAccountMode
  2592.                 && (mAccount == null || !mAccount.isAvailable(this))) {
  2593.             Log.i(K9.LOG_TAG, "not opening MessageList of unavailable account");
  2594.             onAccountUnavailable();
  2595.             return false;
  2596.         }
  2597.  
  2598.         if (mSingleFolderMode) {
  2599.             mFolderName = mSearch.getFolderNames().get(0);
  2600.         }
  2601.  
  2602.         // now we know if we are in single account mode and need a subtitle
  2603.         mActionBarSubTitle.setVisibility((!mSingleFolderMode) ? View.GONE
  2604.                 : View.VISIBLE);
  2605.  
  2606.         return true;
  2607.     }
  2608.  
  2609.     @Override
  2610.     public void onPause() {
  2611.         super.onPause();
  2612.  
  2613.         StorageManager.getInstance(getApplication()).removeListener(
  2614.                 mStorageListener);
  2615.         MessagingController.getInstance(getApplication()).removeListener(
  2616.                 mAdapter.mListener);
  2617.         mAdapter.mListener.onPause(this);
  2618.  
  2619.         MessagingController.getInstance(getApplication()).removeListener(
  2620.                 mListener_Accounts);
  2621.         StorageManager.getInstance(getApplication()).removeListener(
  2622.                 storageListener);
  2623.         mListener_Accounts.onPause(this);
  2624.     }
  2625.  
  2626.     @Override
  2627.     public void onSaveInstanceState(Bundle outState) {
  2628.         super.onSaveInstanceState(outState);
  2629.  
  2630.         outState.putSerializable(STATE_DISPLAY_MODE, mDisplayMode);
  2631.         outState.putBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED,
  2632.                 mMessageListWasDisplayed);
  2633.     }
  2634.  
  2635.     public void onExport(final boolean includeGlobals, final Account account) {
  2636.  
  2637.         // TODO, prompt to allow a user to choose which accounts to export
  2638.         Set<String> accountUuids = null;
  2639.         if (account != null) {
  2640.             accountUuids = new HashSet<String>();
  2641.             accountUuids.add(account.getUuid());
  2642.         }
  2643.  
  2644.         ExportAsyncTask asyncTask = new ExportAsyncTask(this, includeGlobals,
  2645.                 accountUuids);
  2646.         setNonConfigurationInstance(asyncTask);
  2647.         asyncTask.execute();
  2648.     }
  2649.  
  2650.     @Override
  2651.     public void onRestoreInstanceState(Bundle savedInstanceState) {
  2652.         mMessageListWasDisplayed = savedInstanceState
  2653.                 .getBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED);
  2654.     }
  2655.  
  2656.     private void initializeActionBar() {
  2657.         mActionBar = getActionBar();
  2658.  
  2659.         mActionBar.setDisplayShowCustomEnabled(true);
  2660.         mActionBar.setCustomView(R.layout.actionbar_custom);
  2661.  
  2662.         View customView = mActionBar.getCustomView();
  2663.         mActionBarMessageList = customView
  2664.                 .findViewById(R.id.actionbar_message_list);
  2665.         mActionBarMessageView = customView
  2666.                 .findViewById(R.id.actionbar_message_view);
  2667.         mActionBarSubject = (MessageTitleView) customView
  2668.                 .findViewById(R.id.message_title_view);
  2669.         mActionBarTitle = (TextView) customView
  2670.                 .findViewById(R.id.actionbar_title_first);
  2671.         mActionBarSubTitle = (TextView) customView
  2672.                 .findViewById(R.id.actionbar_title_sub);
  2673.         mActionBarUnread = (TextView) customView
  2674.                 .findViewById(R.id.actionbar_unread_count);
  2675.         mActionBarProgress = (ProgressBar) customView
  2676.                 .findViewById(R.id.actionbar_progress);
  2677.         mActionButtonIndeterminateProgress = getLayoutInflater().inflate(
  2678.                 R.layout.actionbar_indeterminate_progress_actionview, null);
  2679.  
  2680.         mActionBar.setDisplayHomeAsUpEnabled(true);
  2681.     }
  2682.  
  2683.     @Override
  2684.     public void setupGestureDetector(OnSwipeGestureListener listener) {
  2685.         mBase.setupGestureDetector(listener);
  2686.     }
  2687.  
  2688.     @Override
  2689.     public boolean dispatchKeyEvent(KeyEvent event) {
  2690.         boolean ret = false;
  2691.         if (KeyEvent.ACTION_DOWN == event.getAction()) {
  2692.             ret = onCustomKeyDown(event.getKeyCode(), event);
  2693.         }
  2694.         if (!ret) {
  2695.             ret = super.dispatchKeyEvent(event);
  2696.         }
  2697.         return ret;
  2698.     }
  2699.  
  2700.     @Override
  2701.     public void onBackPressed() {
  2702.         if (mDisplayMode == DisplayMode.MESSAGE_VIEW
  2703.                 && mMessageListWasDisplayed) {
  2704.             showMessageList();
  2705.         } else {
  2706.             super.onBackPressed();
  2707.         }
  2708.    
  2709.         mDrawerToggle.setDrawerIndicatorEnabled(true);
  2710.        
  2711.         mDrawerLayout.closeDrawer(Gravity.START);
  2712.    
  2713.     }
  2714.  
  2715.     /**
  2716.      * Handle hotkeys
  2717.      *
  2718.      * <p>
  2719.      * This method is called by {@link #dispatchKeyEvent(KeyEvent)} before any
  2720.      * view had the chance to consume this key event.
  2721.      * </p>
  2722.      *
  2723.      * @param keyCode
  2724.      *            The value in {@code event.getKeyCode()}.
  2725.      * @param event
  2726.      *            Description of the key event.
  2727.      *
  2728.      * @return {@code true} if this event was consumed.
  2729.      */
  2730.     public boolean onCustomKeyDown(final int keyCode, final KeyEvent event) {
  2731.         switch (keyCode) {
  2732.         case KeyEvent.KEYCODE_VOLUME_UP: {
  2733.             if (mMessageViewFragment != null
  2734.                     && mDisplayMode != DisplayMode.MESSAGE_LIST
  2735.                     && K9.useVolumeKeysForNavigationEnabled()) {
  2736.                 showPreviousMessage();
  2737.                 return true;
  2738.             } else if (mDisplayMode != DisplayMode.MESSAGE_VIEW
  2739.                     && K9.useVolumeKeysForListNavigationEnabled()) {
  2740.                 mMessageListFragment.onMoveUp();
  2741.                 return true;
  2742.             }
  2743.  
  2744.             break;
  2745.         }
  2746.         case KeyEvent.KEYCODE_VOLUME_DOWN: {
  2747.             if (mMessageViewFragment != null
  2748.                     && mDisplayMode != DisplayMode.MESSAGE_LIST
  2749.                     && K9.useVolumeKeysForNavigationEnabled()) {
  2750.                 showNextMessage();
  2751.                 return true;
  2752.             } else if (mDisplayMode != DisplayMode.MESSAGE_VIEW
  2753.                     && K9.useVolumeKeysForListNavigationEnabled()) {
  2754.                 mMessageListFragment.onMoveDown();
  2755.                 return true;
  2756.             }
  2757.  
  2758.             break;
  2759.         }
  2760.         case KeyEvent.KEYCODE_C: {
  2761.             mMessageListFragment.onCompose();
  2762.             return true;
  2763.         }
  2764.         case KeyEvent.KEYCODE_Q: {
  2765.             if (mMessageListFragment != null
  2766.                     && mMessageListFragment.isSingleAccountMode()) {
  2767.                 onShowFolderList();
  2768.             }
  2769.             return true;
  2770.         }
  2771.         case KeyEvent.KEYCODE_O: {
  2772.             mMessageListFragment.onCycleSort();
  2773.             return true;
  2774.         }
  2775.         case KeyEvent.KEYCODE_I: {
  2776.             mMessageListFragment.onReverseSort();
  2777.             return true;
  2778.         }
  2779.         case KeyEvent.KEYCODE_DEL:
  2780.         case KeyEvent.KEYCODE_D: {
  2781.             if (mDisplayMode == DisplayMode.MESSAGE_LIST) {
  2782.                 mMessageListFragment.onDelete();
  2783.             } else if (mMessageViewFragment != null) {
  2784.                 mMessageViewFragment.onDelete();
  2785.             }
  2786.             return true;
  2787.         }
  2788.         case KeyEvent.KEYCODE_S: {
  2789.             mMessageListFragment.toggleMessageSelect();
  2790.             return true;
  2791.         }
  2792.         case KeyEvent.KEYCODE_G: {
  2793.             if (mDisplayMode == DisplayMode.MESSAGE_LIST) {
  2794.                 mMessageListFragment.onToggleFlagged();
  2795.             } else if (mMessageViewFragment != null) {
  2796.                 mMessageViewFragment.onToggleFlagged();
  2797.             }
  2798.             return true;
  2799.         }
  2800.         case KeyEvent.KEYCODE_M: {
  2801.             if (mDisplayMode == DisplayMode.MESSAGE_LIST) {
  2802.                 mMessageListFragment.onMove();
  2803.             } else if (mMessageViewFragment != null) {
  2804.                 mMessageViewFragment.onMove();
  2805.             }
  2806.             return true;
  2807.         }
  2808.         case KeyEvent.KEYCODE_V: {
  2809.             if (mDisplayMode == DisplayMode.MESSAGE_LIST) {
  2810.                 mMessageListFragment.onArchive();
  2811.             } else if (mMessageViewFragment != null) {
  2812.                 mMessageViewFragment.onArchive();
  2813.             }
  2814.             return true;
  2815.         }
  2816.         case KeyEvent.KEYCODE_Y: {
  2817.             if (mDisplayMode == DisplayMode.MESSAGE_LIST) {
  2818.                 mMessageListFragment.onCopy();
  2819.             } else if (mMessageViewFragment != null) {
  2820.                 mMessageViewFragment.onCopy();
  2821.             }
  2822.             return true;
  2823.         }
  2824.         case KeyEvent.KEYCODE_Z: {
  2825.             if (mDisplayMode == DisplayMode.MESSAGE_LIST) {
  2826.                 mMessageListFragment.onToggleRead();
  2827.             } else if (mMessageViewFragment != null) {
  2828.                 mMessageViewFragment.onToggleRead();
  2829.             }
  2830.             return true;
  2831.         }
  2832.         case KeyEvent.KEYCODE_F: {
  2833.             if (mMessageViewFragment != null) {
  2834.                 mMessageViewFragment.onForward();
  2835.             }
  2836.             return true;
  2837.         }
  2838.         case KeyEvent.KEYCODE_A: {
  2839.             if (mMessageViewFragment != null) {
  2840.                 mMessageViewFragment.onReplyAll();
  2841.             }
  2842.             return true;
  2843.         }
  2844.         case KeyEvent.KEYCODE_R: {
  2845.             if (mMessageViewFragment != null) {
  2846.                 mMessageViewFragment.onReply();
  2847.             }
  2848.             return true;
  2849.         }
  2850.         case KeyEvent.KEYCODE_J:
  2851.         case KeyEvent.KEYCODE_P: {
  2852.             if (mMessageViewFragment != null) {
  2853.                 showPreviousMessage();
  2854.             }
  2855.             return true;
  2856.         }
  2857.         case KeyEvent.KEYCODE_N:
  2858.         case KeyEvent.KEYCODE_K: {
  2859.             if (mMessageViewFragment != null) {
  2860.                 showNextMessage();
  2861.             }
  2862.             return true;
  2863.         }
  2864.         /*
  2865.          * FIXME case KeyEvent.KEYCODE_Z: { mMessageViewFragment.zoom(event);
  2866.          * return true; }
  2867.          */
  2868.         case KeyEvent.KEYCODE_H: {
  2869.             Toast toast = Toast.makeText(this, R.string.message_list_help_key,
  2870.                     Toast.LENGTH_LONG);
  2871.             toast.show();
  2872.             return true;
  2873.         }
  2874.  
  2875.         }
  2876.  
  2877.         return false;
  2878.     }
  2879.  
  2880.     @Override
  2881.     public boolean onKeyUp(int keyCode, KeyEvent event) {
  2882.         // Swallow these events too to avoid the audible notification of a
  2883.         // volume change
  2884.         if (K9.useVolumeKeysForListNavigationEnabled()) {
  2885.             if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
  2886.                     || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
  2887.                 if (K9.DEBUG)
  2888.                     Log.v(K9.LOG_TAG, "Swallowed key up.");
  2889.                 return true;
  2890.             }
  2891.         }
  2892.         return super.onKeyUp(keyCode, event);
  2893.     }
  2894.  
  2895.     private void onShowFolderList() {
  2896.         FolderList.actionHandleAccount(this, mAccount);
  2897.         finish();
  2898.     }
  2899.  
  2900.     @Override
  2901.     public boolean onOptionsItemSelected(android.view.MenuItem item) {
  2902.         int itemId = item.getItemId();
  2903.  
  2904.         if (item.getItemId() == android.R.id.home) {
  2905.  
  2906.             if (mDrawerLayout.isDrawerOpen(mDrawerLinear)) {
  2907.                 mDrawerLayout.closeDrawer(mDrawerLinear);
  2908.             } else {
  2909.                 mDrawerLayout.openDrawer(mDrawerLinear);
  2910.             }
  2911.         }
  2912.  
  2913.         switch (itemId) {
  2914.  
  2915.         case R.id.compose: {
  2916.             mMessageListFragment.onCompose();
  2917.             return true;
  2918.         }
  2919.         case R.id.toggle_message_view_theme: {
  2920.             onToggleTheme();
  2921.             return true;
  2922.         }
  2923.         // MessageList
  2924.         case R.id.check_mail: {
  2925.             mMessageListFragment.checkMail();
  2926.             return true;
  2927.         }
  2928.         case R.id.set_sort_date: {
  2929.             mMessageListFragment.changeSort(SortType.SORT_DATE);
  2930.             return true;
  2931.         }
  2932.         case R.id.set_sort_arrival: {
  2933.             mMessageListFragment.changeSort(SortType.SORT_ARRIVAL);
  2934.             return true;
  2935.         }
  2936.         case R.id.set_sort_subject: {
  2937.             mMessageListFragment.changeSort(SortType.SORT_SUBJECT);
  2938.             return true;
  2939.         }
  2940.         case R.id.set_sort_sender: {
  2941.             mMessageListFragment.changeSort(SortType.SORT_SENDER);
  2942.             return true;
  2943.         }
  2944.         case R.id.set_sort_flag: {
  2945.             mMessageListFragment.changeSort(SortType.SORT_FLAGGED);
  2946.             return true;
  2947.         }
  2948.         case R.id.set_sort_unread: {
  2949.             mMessageListFragment.changeSort(SortType.SORT_UNREAD);
  2950.             return true;
  2951.         }
  2952.         case R.id.set_sort_attach: {
  2953.             mMessageListFragment.changeSort(SortType.SORT_ATTACHMENT);
  2954.             return true;
  2955.         }
  2956.         case R.id.select_all: {
  2957.             mMessageListFragment.selectAll();
  2958.             return true;
  2959.         }
  2960.         case R.id.app_settings: {
  2961.             onEditPrefs();
  2962.             return true;
  2963.         }
  2964.         case R.id.account_settings: {
  2965.             onEditAccount();
  2966.             return true;
  2967.         }
  2968.         case R.id.search: {
  2969.             mMessageListFragment.onSearchRequested();
  2970.             return true;
  2971.         }
  2972.         case R.id.search_remote: {
  2973.             mMessageListFragment.onRemoteSearch();
  2974.             return true;
  2975.         }
  2976.         case R.id.mark_all_as_read: {
  2977.             mMessageListFragment.markAllAsRead();
  2978.             return true;
  2979.         }
  2980.         case R.id.show_folder_list: {
  2981.             onShowFolderList();
  2982.             return true;
  2983.         }
  2984.         // MessageView
  2985.         case R.id.next_message: {
  2986.             showNextMessage();
  2987.             return true;
  2988.         }
  2989.         case R.id.previous_message: {
  2990.             showPreviousMessage();
  2991.             return true;
  2992.         }
  2993.         case R.id.delete: {
  2994.             mMessageViewFragment.onDelete();
  2995.             return true;
  2996.         }
  2997.         case R.id.reply: {
  2998.             mMessageViewFragment.onReply();
  2999.             return true;
  3000.         }
  3001.         case R.id.reply_all: {
  3002.             mMessageViewFragment.onReplyAll();
  3003.             return true;
  3004.         }
  3005.         case R.id.forward: {
  3006.             mMessageViewFragment.onForward();
  3007.             return true;
  3008.         }
  3009.         case R.id.share: {
  3010.             mMessageViewFragment.onSendAlternate();
  3011.             return true;
  3012.         }
  3013.         case R.id.toggle_unread: {
  3014.             mMessageViewFragment.onToggleRead();
  3015.             return true;
  3016.         }
  3017.         case R.id.archive:
  3018.         case R.id.refile_archive: {
  3019.             mMessageViewFragment.onArchive();
  3020.             return true;
  3021.         }
  3022.         case R.id.spam:
  3023.         case R.id.refile_spam: {
  3024.             mMessageViewFragment.onSpam();
  3025.             return true;
  3026.         }
  3027.         case R.id.move:
  3028.         case R.id.refile_move: {
  3029.             mMessageViewFragment.onMove();
  3030.             return true;
  3031.         }
  3032.         case R.id.copy:
  3033.         case R.id.refile_copy: {
  3034.             mMessageViewFragment.onCopy();
  3035.             return true;
  3036.         }
  3037.         case R.id.select_text: {
  3038.             mMessageViewFragment.onSelectText();
  3039.             return true;
  3040.         }
  3041.         case R.id.show_headers:
  3042.         case R.id.hide_headers: {
  3043.             mMessageViewFragment.onToggleAllHeadersView();
  3044.             updateMenu();
  3045.             return true;
  3046.         }
  3047.         }
  3048.  
  3049.         if (!mSingleFolderMode) {
  3050.             // None of the options after this point are "safe" for search
  3051.             // results
  3052.             // TODO: This is not true for "unread" and "starred" searches in
  3053.             // regular folders
  3054.             return false;
  3055.         }
  3056.  
  3057.         switch (itemId) {
  3058.         case R.id.send_messages: {
  3059.             mMessageListFragment.onSendPendingMessages();
  3060.             return true;
  3061.         }
  3062.         case R.id.folder_settings: {
  3063.             if (mFolderName != null) {
  3064.                 FolderSettings.actionSettings(this, mAccount, mFolderName);
  3065.             }
  3066.             return true;
  3067.         }
  3068.         case R.id.expunge: {
  3069.             mMessageListFragment.onExpunge();
  3070.             return true;
  3071.         }
  3072.         default: {
  3073.             return super.onOptionsItemSelected(item);
  3074.         }
  3075.         }
  3076.     }
  3077.  
  3078.     @Override
  3079.     public boolean onCreateOptionsMenu(android.view.Menu menu) {
  3080.         getMenuInflater().inflate(R.menu.message_list_option, menu);
  3081.         mMenu = menu;
  3082.         mMenuButtonCheckMail = menu.findItem(R.id.check_mail);
  3083.         return true;
  3084.     }
  3085.  
  3086.     @Override
  3087.     public boolean onPrepareOptionsMenu(Menu menu) {
  3088.         configureMenu(menu);
  3089.         return true;
  3090.     }
  3091.  
  3092.     /**
  3093.      * Hide menu items not appropriate for the current context.
  3094.      *
  3095.      * <p>
  3096.      * <strong>Note:</strong> Please adjust the comments in
  3097.      * {@code res/menu/message_list_option.xml} if you change the visibility of
  3098.      * a menu item in this method.
  3099.      * </p>
  3100.      *
  3101.      * @param mMenu2
  3102.      *            The {@link Menu} instance that should be modified. May be
  3103.      *            {@code null}; in that case the method does nothing and
  3104.      *            immediately returns.
  3105.      */
  3106.     private void configureMenu(android.view.Menu mMenu2) {
  3107.         if (mMenu2 == null) {
  3108.             return;
  3109.         }
  3110.  
  3111.         // Set visibility of account/folder settings menu items
  3112.         if (mMessageListFragment == null) {
  3113.             mMenu2.findItem(R.id.account_settings).setVisible(false);
  3114.             mMenu2.findItem(R.id.folder_settings).setVisible(false);
  3115.         } else {
  3116.             mMenu2.findItem(R.id.account_settings).setVisible(
  3117.                     mMessageListFragment.isSingleAccountMode());
  3118.             mMenu2.findItem(R.id.folder_settings).setVisible(
  3119.                     mMessageListFragment.isSingleFolderMode());
  3120.         }
  3121.  
  3122.         /*
  3123.          * Set visibility of menu items related to the message view
  3124.          */
  3125.  
  3126.         if (mDisplayMode == DisplayMode.MESSAGE_LIST
  3127.                 || mMessageViewFragment == null
  3128.                 || !mMessageViewFragment.isInitialized()) {
  3129.             mMenu2.findItem(R.id.next_message).setVisible(false);
  3130.             mMenu2.findItem(R.id.previous_message).setVisible(false);
  3131.             mMenu2.findItem(R.id.single_message_options).setVisible(false);
  3132.             mMenu2.findItem(R.id.delete).setVisible(false);
  3133.             mMenu2.findItem(R.id.compose).setVisible(false);
  3134.             mMenu2.findItem(R.id.archive).setVisible(false);
  3135.             mMenu2.findItem(R.id.move).setVisible(false);
  3136.             mMenu2.findItem(R.id.copy).setVisible(false);
  3137.             mMenu2.findItem(R.id.spam).setVisible(false);
  3138.             mMenu2.findItem(R.id.refile).setVisible(false);
  3139.             mMenu2.findItem(R.id.toggle_unread).setVisible(false);
  3140.             mMenu2.findItem(R.id.select_text).setVisible(false);
  3141.             mMenu2.findItem(R.id.toggle_message_view_theme).setVisible(false);
  3142.             mMenu2.findItem(R.id.show_headers).setVisible(false);
  3143.             mMenu2.findItem(R.id.hide_headers).setVisible(false);
  3144.         } else {
  3145.             // hide prev/next buttons in split mode
  3146.             if (mDisplayMode != DisplayMode.MESSAGE_VIEW) {
  3147.                 mMenu2.findItem(R.id.next_message).setVisible(false);
  3148.                 mMenu2.findItem(R.id.previous_message).setVisible(false);
  3149.             } else {
  3150.                 MessageReference ref = mMessageViewFragment
  3151.                         .getMessageReference();
  3152.                 boolean initialized = (mMessageListFragment != null && mMessageListFragment
  3153.                         .isLoadFinished());
  3154.                 boolean canDoPrev = (initialized && !mMessageListFragment
  3155.                         .isFirst(ref));
  3156.                 boolean canDoNext = (initialized && !mMessageListFragment
  3157.                         .isLast(ref));
  3158.  
  3159.                 MenuItem prev = mMenu2.findItem(R.id.previous_message);
  3160.                 prev.setEnabled(canDoPrev);
  3161.                 // prev.getIcon().setAlpha(canDoPrev ? 255 : 127);
  3162.  
  3163.                 // MenuItem next = menu.findItem(R.id.next_message);
  3164.                 // next.setEnabled(canDoNext);
  3165.                 // next.getIcon().setAlpha(canDoNext ? 255 : 127);
  3166.             }
  3167.  
  3168.             MenuItem toggleTheme = mMenu2
  3169.                     .findItem(R.id.toggle_message_view_theme);
  3170.             if (K9.useFixedMessageViewTheme()) {
  3171.                 toggleTheme.setVisible(false);
  3172.             } else {
  3173.                 // Set title of menu item to switch to dark/light theme
  3174.                 if (K9.getK9MessageViewTheme() == K9.Theme.DARK) {
  3175.                     toggleTheme
  3176.                             .setTitle(R.string.message_view_theme_action_light);
  3177.                 } else {
  3178.                     toggleTheme
  3179.                             .setTitle(R.string.message_view_theme_action_dark);
  3180.                 }
  3181.                 toggleTheme.setVisible(true);
  3182.             }
  3183.  
  3184.             // Set title of menu item to toggle the read state of the currently
  3185.             // displayed message
  3186.             if (mMessageViewFragment.isMessageRead()) {
  3187.                 mMenu2.findItem(R.id.toggle_unread).setTitle(
  3188.                         R.string.mark_as_unread_action);
  3189.             } else {
  3190.                 mMenu2.findItem(R.id.toggle_unread).setTitle(
  3191.                         R.string.mark_as_read_action);
  3192.             }
  3193.  
  3194.             // Jellybean has built-in long press selection support
  3195.             mMenu2.findItem(R.id.select_text).setVisible(
  3196.                     Build.VERSION.SDK_INT < 16);
  3197.  
  3198.             mMenu2.findItem(R.id.delete).setVisible(
  3199.                     K9.isMessageViewDeleteActionVisible());
  3200.  
  3201.             /*
  3202.              * Set visibility of copy, move, archive, spam in action bar and
  3203.              * refile submenu
  3204.              */
  3205.             if (mMessageViewFragment.isCopyCapable()) {
  3206.                 mMenu2.findItem(R.id.copy).setVisible(
  3207.                         K9.isMessageViewCopyActionVisible());
  3208.                 mMenu2.findItem(R.id.refile_copy).setVisible(true);
  3209.             } else {
  3210.                 mMenu2.findItem(R.id.copy).setVisible(false);
  3211.                 mMenu2.findItem(R.id.refile_copy).setVisible(false);
  3212.             }
  3213.  
  3214.             if (mMessageViewFragment.isMoveCapable()) {
  3215.                 boolean canMessageBeArchived = mMessageViewFragment
  3216.                         .canMessageBeArchived();
  3217.                 boolean canMessageBeMovedToSpam = mMessageViewFragment
  3218.                         .canMessageBeMovedToSpam();
  3219.  
  3220.                 mMenu2.findItem(R.id.move).setVisible(
  3221.                         K9.isMessageViewMoveActionVisible());
  3222.                 mMenu2.findItem(R.id.archive).setVisible(
  3223.                         canMessageBeArchived
  3224.                                 && K9.isMessageViewArchiveActionVisible());
  3225.                 mMenu2.findItem(R.id.spam).setVisible(
  3226.                         canMessageBeMovedToSpam
  3227.                                 && K9.isMessageViewSpamActionVisible());
  3228.  
  3229.                 mMenu2.findItem(R.id.refile_move).setVisible(true);
  3230.                 mMenu2.findItem(R.id.refile_archive).setVisible(
  3231.                         canMessageBeArchived);
  3232.                 mMenu2.findItem(R.id.refile_spam).setVisible(
  3233.                         canMessageBeMovedToSpam);
  3234.             } else {
  3235.                 mMenu2.findItem(R.id.move).setVisible(false);
  3236.                 mMenu2.findItem(R.id.archive).setVisible(false);
  3237.                 mMenu2.findItem(R.id.spam).setVisible(false);
  3238.  
  3239.                 mMenu2.findItem(R.id.refile).setVisible(false);
  3240.             }
  3241.  
  3242.             if (mMessageViewFragment.allHeadersVisible()) {
  3243.                 mMenu2.findItem(R.id.show_headers).setVisible(false);
  3244.             } else {
  3245.                 mMenu2.findItem(R.id.hide_headers).setVisible(false);
  3246.             }
  3247.         }
  3248.  
  3249.         /*
  3250.          * Set visibility of menu items related to the message list
  3251.          */
  3252.  
  3253.         // Hide both search menu items by default and enable one when
  3254.         // appropriate
  3255.         mMenu2.findItem(R.id.search).setVisible(false);
  3256.         mMenu2.findItem(R.id.search_remote).setVisible(false);
  3257.  
  3258.         if (mDisplayMode == DisplayMode.MESSAGE_VIEW
  3259.                 || mMessageListFragment == null
  3260.                 || !mMessageListFragment.isInitialized()) {
  3261.             mMenu2.findItem(R.id.check_mail).setVisible(false);
  3262.             mMenu2.findItem(R.id.set_sort).setVisible(false);
  3263.             mMenu2.findItem(R.id.select_all).setVisible(false);
  3264.             mMenu2.findItem(R.id.send_messages).setVisible(false);
  3265.             mMenu2.findItem(R.id.expunge).setVisible(false);
  3266.             mMenu2.findItem(R.id.mark_all_as_read).setVisible(false);
  3267.             mMenu2.findItem(R.id.show_folder_list).setVisible(false);
  3268.         } else {
  3269.             mMenu2.findItem(R.id.set_sort).setVisible(true);
  3270.             mMenu2.findItem(R.id.select_all).setVisible(true);
  3271.             mMenu2.findItem(R.id.compose).setVisible(true);
  3272.             mMenu2.findItem(R.id.mark_all_as_read).setVisible(
  3273.                     mMessageListFragment.isMarkAllAsReadSupported());
  3274.  
  3275.             if (!mMessageListFragment.isSingleAccountMode()) {
  3276.                 mMenu2.findItem(R.id.expunge).setVisible(false);
  3277.                 mMenu2.findItem(R.id.send_messages).setVisible(false);
  3278.                 mMenu2.findItem(R.id.show_folder_list).setVisible(false);
  3279.             } else {
  3280.                 mMenu2.findItem(R.id.send_messages).setVisible(
  3281.                         mMessageListFragment.isOutbox());
  3282.                 mMenu2.findItem(R.id.expunge).setVisible(
  3283.                         mMessageListFragment.isRemoteFolder()
  3284.                                 && mMessageListFragment
  3285.                                         .isAccountExpungeCapable());
  3286.                 mMenu2.findItem(R.id.show_folder_list).setVisible(true);
  3287.             }
  3288.  
  3289.             mMenu2.findItem(R.id.check_mail).setVisible(
  3290.                     mMessageListFragment.isCheckMailSupported());
  3291.  
  3292.             // If this is an explicit local search, show the option to search on
  3293.             // the server
  3294.             if (!mMessageListFragment.isRemoteSearch()
  3295.                     && mMessageListFragment.isRemoteSearchAllowed()) {
  3296.                 mMenu2.findItem(R.id.search_remote).setVisible(true);
  3297.             } else if (!mMessageListFragment.isManualSearch()) {
  3298.                 mMenu2.findItem(R.id.search).setVisible(true);
  3299.             }
  3300.         }
  3301.     }
  3302.  
  3303.     protected void onAccountUnavailable() {
  3304.         finish();
  3305.         // TODO inform user about account unavailability using Toast
  3306.         Accounts.listAccounts(this);
  3307.     }
  3308.  
  3309.     public void setActionBarTitle(String title) {
  3310.         mActionBarTitle.setText(title);
  3311.     }
  3312.  
  3313.     public void setActionBarSubTitle(String subTitle) {
  3314.         mActionBarSubTitle.setText(subTitle);
  3315.     }
  3316.  
  3317.     public void setActionBarUnread(int unread) {
  3318.         if (unread == 0) {
  3319.             mActionBarUnread.setVisibility(View.GONE);
  3320.         } else {
  3321.             mActionBarUnread.setVisibility(View.VISIBLE);
  3322.             mActionBarUnread.setText(Integer.toString(unread));
  3323.  
  3324.         }
  3325.     }
  3326.  
  3327.     @Override
  3328.     public void setMessageListTitle(String title) {
  3329.         setActionBarTitle(title);
  3330.     }
  3331.  
  3332.     @Override
  3333.     public void setMessageListSubTitle(String subTitle) {
  3334.         setActionBarSubTitle(subTitle);
  3335.     }
  3336.  
  3337.     @Override
  3338.     public void setUnreadCount(int unread) {
  3339.         setActionBarUnread(unread);
  3340.     }
  3341.  
  3342.     @Override
  3343.     public void setMessageListProgress(int progress) {
  3344.         setProgress(progress);
  3345.     }
  3346.  
  3347.     @Override
  3348.     public void openMessage(MessageReference messageReference) {
  3349.         Preferences prefs = Preferences.getPreferences(getApplicationContext());
  3350.         Account account = prefs.getAccount(messageReference.accountUuid);
  3351.         String folderName = messageReference.folderName;
  3352.  
  3353.         if (folderName.equals(account.getDraftsFolderName())) {
  3354.             MessageCompose.actionEditDraft(this, messageReference);
  3355.         } else {
  3356.             mMessageViewContainer.removeView(mMessageViewPlaceHolder);
  3357.  
  3358.             if (mMessageListFragment != null) {
  3359.                 mMessageListFragment.setActiveMessage(messageReference);
  3360.             }
  3361.  
  3362.             MessageViewFragment fragment = MessageViewFragment
  3363.                     .newInstance(messageReference);
  3364.             FragmentTransaction ft = getFragmentManager().beginTransaction();
  3365.             ft.replace(R.id.message_view_container, fragment);
  3366.             mMessageViewFragment = fragment;
  3367.             ft.commit();
  3368.  
  3369.             if (mDisplayMode != DisplayMode.SPLIT_VIEW) {
  3370.                 showMessageView();
  3371.             }
  3372.         }
  3373.     }
  3374.  
  3375.     @Override
  3376.     public void onResendMessage(Message message) {
  3377.         MessageCompose.actionEditDraft(this, message.makeMessageReference());
  3378.     }
  3379.  
  3380.     @Override
  3381.     public void onForward(Message message) {
  3382.         MessageCompose.actionForward(this, message.getFolder().getAccount(),
  3383.                 message, null);
  3384.     }
  3385.  
  3386.     @Override
  3387.     public void onReply(Message message) {
  3388.         MessageCompose.actionReply(this, message.getFolder().getAccount(),
  3389.                 message, false, null);
  3390.     }
  3391.  
  3392.     @Override
  3393.     public void onReplyAll(Message message) {
  3394.         MessageCompose.actionReply(this, message.getFolder().getAccount(),
  3395.                 message, true, null);
  3396.     }
  3397.  
  3398.     @Override
  3399.     public void onCompose(Account account) {
  3400.         MessageCompose.actionCompose(this, account);
  3401.     }
  3402.  
  3403.     @Override
  3404.     public void showMoreFromSameSender(String senderAddress) {
  3405.         LocalSearch tmpSearch = new LocalSearch("From " + senderAddress);
  3406.         tmpSearch.addAccountUuids(mSearch.getAccountUuids());
  3407.         tmpSearch.and(Searchfield.SENDER, senderAddress, Attribute.CONTAINS);
  3408.  
  3409.         MessageListFragment fragment = MessageListFragment.newInstance(
  3410.                 tmpSearch, false, false);
  3411.  
  3412.         addMessageListFragment(fragment, true);
  3413.     }
  3414.  
  3415.     @Override
  3416.     public void onBackStackChanged() {
  3417.         findFragments();
  3418.  
  3419.         if (mDisplayMode == DisplayMode.SPLIT_VIEW) {
  3420.             showMessageViewPlaceHolder();
  3421.         }
  3422.  
  3423.         configureMenu(mMenu);
  3424.     }
  3425.  
  3426.     @Override
  3427.     public void onSwipeRightToLeft(MotionEvent e1, MotionEvent e2) {
  3428.         if (mMessageListFragment != null
  3429.                 && mDisplayMode != DisplayMode.MESSAGE_VIEW) {
  3430.             mMessageListFragment.onSwipeRightToLeft(e1, e2);
  3431.         }
  3432.     }
  3433.  
  3434.     @Override
  3435.     public void onSwipeLeftToRight(MotionEvent e1, MotionEvent e2) {
  3436.         if (mMessageListFragment != null
  3437.                 && mDisplayMode != DisplayMode.MESSAGE_VIEW) {
  3438.             mMessageListFragment.onSwipeLeftToRight(e1, e2);
  3439.         }
  3440.     }
  3441.  
  3442.     private final class StorageListenerImplementation implements
  3443.             StorageManager.StorageListener {
  3444.         @Override
  3445.         public void onUnmount(String providerId) {
  3446.             if (mAccount != null
  3447.                     && providerId.equals(mAccount.getLocalStorageProviderId())) {
  3448.                 runOnUiThread(new Runnable() {
  3449.                     @Override
  3450.                     public void run() {
  3451.                         onAccountUnavailable();
  3452.                     }
  3453.                 });
  3454.             }
  3455.         }
  3456.  
  3457.         @Override
  3458.         public void onMount(String providerId) {
  3459.             // no-op
  3460.         }
  3461.     }
  3462.  
  3463.     private void addMessageListFragment(MessageListFragment fragment,
  3464.             boolean addToBackStack) {
  3465.         FragmentTransaction ft = getFragmentManager().beginTransaction();
  3466.  
  3467.         ft.replace(R.id.message_list_container, fragment);
  3468.         if (addToBackStack)
  3469.             ft.addToBackStack(null);
  3470.  
  3471.         mMessageListFragment = fragment;
  3472.  
  3473.         int transactionId = ft.commit();
  3474.         if (transactionId >= 0 && mFirstBackStackId < 0) {
  3475.             mFirstBackStackId = transactionId;
  3476.         }
  3477.     }
  3478.  
  3479.     // makes the listviews act as one listview
  3480.     public static void setListViewHeightBasedOnChildren(ListView listView) {
  3481.         ListAdapter listAdapter = listView.getAdapter();
  3482.         if (listAdapter == null) {
  3483.             // pre-condition
  3484.             return;
  3485.         }
  3486.  
  3487.         int totalHeight = 0;
  3488.         for (int i = 0; i < listAdapter.getCount(); i++) {
  3489.             View listItem = listAdapter.getView(i, null, listView);
  3490.             listItem.measure(0, 0);
  3491.             totalHeight += listItem.getMeasuredHeight();
  3492.         }
  3493.  
  3494.         ViewGroup.LayoutParams params = listView.getLayoutParams();
  3495.         params.height = totalHeight
  3496.                 + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
  3497.         listView.setLayoutParams(params);
  3498.         listView.requestLayout();
  3499.     }
  3500.  
  3501.     @Override
  3502.     public boolean startSearch(Account account, String folderName) {
  3503.         // If this search was started from a MessageList of a single folder,
  3504.         // pass along that folder info
  3505.         // so that we can enable remote search.
  3506.         if (account != null && folderName != null) {
  3507.             final Bundle appData = new Bundle();
  3508.             appData.putString(EXTRA_SEARCH_ACCOUNT, account.getUuid());
  3509.             appData.putString(EXTRA_SEARCH_FOLDER, folderName);
  3510.             startSearch(null, false, appData, false);
  3511.         } else {
  3512.             // TODO Handle the case where we're searching from within a search
  3513.             // result.
  3514.             startSearch(null, false, null, false);
  3515.         }
  3516.  
  3517.         return true;
  3518.     }
  3519.  
  3520.     @Override
  3521.     public void showThread(Account account, String folderName, long threadRootId) {
  3522.         showMessageViewPlaceHolder();
  3523.  
  3524.         LocalSearch tmpSearch = new LocalSearch();
  3525.         tmpSearch.addAccountUuid(account.getUuid());
  3526.         tmpSearch.and(Searchfield.THREAD_ID, String.valueOf(threadRootId),
  3527.                 Attribute.EQUALS);
  3528.  
  3529.         MessageListFragment fragment = MessageListFragment.newInstance(
  3530.                 tmpSearch, true, false);
  3531.         addMessageListFragment(fragment, true);
  3532.     }
  3533.  
  3534.     private void showMessageViewPlaceHolder() {
  3535.         removeMessageViewFragment();
  3536.  
  3537.         // Add placeholder view if necessary
  3538.         if (mMessageViewPlaceHolder.getParent() == null) {
  3539.             mMessageViewContainer.addView(mMessageViewPlaceHolder);
  3540.         }
  3541.  
  3542.         mMessageListFragment.setActiveMessage(null);
  3543.     }
  3544.  
  3545.     /**
  3546.      * Remove MessageViewFragment if necessary.
  3547.      */
  3548.     private void removeMessageViewFragment() {
  3549.         if (mMessageViewFragment != null) {
  3550.             FragmentTransaction ft = getFragmentManager().beginTransaction();
  3551.             ft.remove(mMessageViewFragment);
  3552.             mMessageViewFragment = null;
  3553.             ft.commit();
  3554.  
  3555.             showDefaultTitleView();
  3556.         }
  3557.     }
  3558.  
  3559.     private void removeMessageListFragment() {
  3560.         if (mMessageViewFragment != null) {
  3561.             FragmentTransaction ft = getFragmentManager().beginTransaction();
  3562.             ft.remove(mMessageListFragment);
  3563.             mMessageListFragment = null;
  3564.             ft.commit();
  3565.         }
  3566.     }
  3567.  
  3568.     @Override
  3569.     public void remoteSearchStarted() {
  3570.         // Remove action button for remote search
  3571.         configureMenu(mMenu);
  3572.     }
  3573.  
  3574.     @Override
  3575.     public void goBack() {
  3576.         FragmentManager fragmentManager = getFragmentManager();
  3577.         if (mDisplayMode == DisplayMode.MESSAGE_VIEW) {
  3578.             showMessageList();
  3579.         } else if (fragmentManager.getBackStackEntryCount() > 0) {
  3580.             fragmentManager.popBackStack();
  3581.         } else if (mMessageListFragment.isManualSearch()) {
  3582.             finish();
  3583.         } else if (!mSingleFolderMode) {
  3584.             onAccounts();
  3585.         } else {
  3586.             onShowFolderList();
  3587.         }
  3588.     }
  3589.  
  3590.     @Override
  3591.     public void enableActionBarProgress(boolean enable) {
  3592.         if (mMenuButtonCheckMail != null && mMenuButtonCheckMail.isVisible()) {
  3593.             mActionBarProgress.setVisibility(View.GONE);
  3594.             if (enable) {
  3595.                 mMenuButtonCheckMail
  3596.                         .setActionView(mActionButtonIndeterminateProgress);
  3597.             } else {
  3598.                 mMenuButtonCheckMail.setActionView(null);
  3599.             }
  3600.         } else {
  3601.             if (mMenuButtonCheckMail != null)
  3602.                 mMenuButtonCheckMail.setActionView(null);
  3603.             if (enable) {
  3604.                 mActionBarProgress.setVisibility(View.VISIBLE);
  3605.             } else {
  3606.                 mActionBarProgress.setVisibility(View.GONE);
  3607.             }
  3608.         }
  3609.     }
  3610.  
  3611.     private void restartActivity() {
  3612.         // restart the current activity, so that the theme change can be applied
  3613.         if (Build.VERSION.SDK_INT < 11) {
  3614.             Intent intent = getIntent();
  3615.             intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  3616.             finish();
  3617.             overridePendingTransition(0, 0); // disable animations to speed up
  3618.                                                 // the switch
  3619.             startActivity(intent);
  3620.             overridePendingTransition(0, 0);
  3621.         } else {
  3622.             recreate();
  3623.         }
  3624.     }
  3625.  
  3626.     @Override
  3627.     public void displayMessageSubject(String subject) {
  3628.         if (mDisplayMode == DisplayMode.MESSAGE_VIEW) {
  3629.             mActionBarSubject.setText(subject);
  3630.         }
  3631.     }
  3632.  
  3633.     @Override
  3634.     public void onReply(Message message, PgpData pgpData) {
  3635.         MessageCompose.actionReply(this, mAccount, message, false,
  3636.                 pgpData.getDecryptedData());
  3637.     }
  3638.  
  3639.     @Override
  3640.     public void onReplyAll(Message message, PgpData pgpData) {
  3641.         MessageCompose.actionReply(this, mAccount, message, true,
  3642.                 pgpData.getDecryptedData());
  3643.     }
  3644.  
  3645.     @Override
  3646.     public void onForward(Message mMessage, PgpData mPgpData) {
  3647.         MessageCompose.actionForward(this, mAccount, mMessage,
  3648.                 mPgpData.getDecryptedData());
  3649.     }
  3650.  
  3651.     @Override
  3652.     public void showNextMessageOrReturn() {
  3653.         if (K9.messageViewReturnToList() || !showLogicalNextMessage()) {
  3654.             if (mDisplayMode == DisplayMode.SPLIT_VIEW) {
  3655.                 showMessageViewPlaceHolder();
  3656.             } else {
  3657.                 showMessageList();
  3658.             }
  3659.         }
  3660.     }
  3661.  
  3662.     /**
  3663.      * Shows the next message in the direction the user was displaying messages.
  3664.      *
  3665.      * @return {@code true}
  3666.      */
  3667.     private boolean showLogicalNextMessage() {
  3668.         boolean result = false;
  3669.         if (mLastDirection == NEXT) {
  3670.             result = showNextMessage();
  3671.         } else if (mLastDirection == PREVIOUS) {
  3672.             result = showPreviousMessage();
  3673.         }
  3674.  
  3675.         if (!result) {
  3676.             result = showNextMessage() || showPreviousMessage();
  3677.         }
  3678.  
  3679.         return result;
  3680.     }
  3681.  
  3682.     @Override
  3683.     public void setProgress(boolean enable) {
  3684.         setProgressBarIndeterminateVisibility(enable);
  3685.     }
  3686.  
  3687.     @Override
  3688.     public void messageHeaderViewAvailable(MessageHeader header) {
  3689.         mActionBarSubject.setMessageHeader(header);
  3690.     }
  3691.  
  3692.     private boolean showNextMessage() {
  3693.         MessageReference ref = mMessageViewFragment.getMessageReference();
  3694.         if (ref != null) {
  3695.             if (mMessageListFragment.openNext(ref)) {
  3696.                 mLastDirection = NEXT;
  3697.                 return true;
  3698.             }
  3699.         }
  3700.         return false;
  3701.     }
  3702.  
  3703.     private boolean showPreviousMessage() {
  3704.         MessageReference ref = mMessageViewFragment.getMessageReference();
  3705.         if (ref != null) {
  3706.             if (mMessageListFragment.openPrevious(ref)) {
  3707.                 mLastDirection = PREVIOUS;
  3708.                 return true;
  3709.             }
  3710.         }
  3711.         return false;
  3712.     }
  3713.  
  3714.     private void showMessageList() {
  3715.         mMessageListWasDisplayed = true;
  3716.         mDisplayMode = DisplayMode.MESSAGE_LIST;
  3717.         mViewSwitcher.showFirstView();
  3718.  
  3719.         mMessageListFragment.setActiveMessage(null);
  3720.  
  3721.         showDefaultTitleView();
  3722.         configureMenu(mMenu);
  3723.     }
  3724.  
  3725.     private void showMessageView() {
  3726.         mDisplayMode = DisplayMode.MESSAGE_VIEW;
  3727.  
  3728.         if (!mMessageListWasDisplayed) {
  3729.             mViewSwitcher.setAnimateFirstView(false);
  3730.         }
  3731.         mViewSwitcher.showSecondView();
  3732.  
  3733.         showMessageTitleView();
  3734.         configureMenu(mMenu);
  3735.     }
  3736.  
  3737.     @Override
  3738.     public void updateMenu() {
  3739.         invalidateOptionsMenu();
  3740.     }
  3741.  
  3742.     @Override
  3743.     public void disableDeleteAction() {
  3744.         mMenu.findItem(R.id.delete).setEnabled(false);
  3745.     }
  3746.  
  3747.     private void onToggleTheme() {
  3748.         if (K9.getK9MessageViewTheme() == K9.Theme.DARK) {
  3749.             K9.setK9MessageViewThemeSetting(K9.Theme.LIGHT);
  3750.         } else {
  3751.             K9.setK9MessageViewThemeSetting(K9.Theme.DARK);
  3752.         }
  3753.  
  3754.         new Thread(new Runnable() {
  3755.             @Override
  3756.             public void run() {
  3757.                 Context appContext = getApplicationContext();
  3758.                 Preferences prefs = Preferences.getPreferences(appContext);
  3759.                 Editor editor = prefs.getPreferences().edit();
  3760.                 K9.save(editor);
  3761.                 editor.commit();
  3762.             }
  3763.         }).start();
  3764.  
  3765.         restartActivity();
  3766.     }
  3767.  
  3768.     private void showDefaultTitleView() {
  3769.         mActionBarMessageView.setVisibility(View.GONE);
  3770.         mActionBarMessageList.setVisibility(View.VISIBLE);
  3771.  
  3772.         if (mMessageListFragment != null) {
  3773.             mMessageListFragment.updateTitle();
  3774.         }
  3775.  
  3776.         mActionBarSubject.setMessageHeader(null);
  3777.     }
  3778.  
  3779.     private void showMessageTitleView() {
  3780.         mActionBarMessageList.setVisibility(View.GONE);
  3781.         mActionBarMessageView.setVisibility(View.VISIBLE);
  3782.  
  3783.         if (mMessageViewFragment != null) {
  3784.             displayMessageSubject(null);
  3785.             mMessageViewFragment.updateTitle();
  3786.         }
  3787.     }
  3788.  
  3789.     @Override
  3790.     public void onSwitchComplete(int displayedChild) {
  3791.         if (displayedChild == 0) {
  3792.             removeMessageViewFragment();
  3793.         }
  3794.     }
  3795.  
  3796.     @Override
  3797.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  3798.         super.onActivityResult(requestCode, resultCode, data);
  3799.  
  3800.         Log.i(K9.LOG_TAG, "onActivityResult requestCode = " + requestCode
  3801.                 + ", resultCode = " + resultCode + ", data = " + data);
  3802.         if (resultCode != RESULT_OK)
  3803.             return;
  3804.         if (data == null) {
  3805.             return;
  3806.         }
  3807.         switch (requestCode) {
  3808.         case ACTIVITY_REQUEST_PICK_SETTINGS_FILE:
  3809.             onImport(data.getData());
  3810.             break;
  3811.         }
  3812.         // handle OpenPGP results from PendingIntents in OpenPGP view
  3813.         // must be handled in this main activity, because
  3814.         // startIntentSenderForResult() does not support Fragments
  3815.         MessageOpenPgpView openPgpView = (MessageOpenPgpView) findViewById(R.id.layout_decrypt_openpgp);
  3816.         if (openPgpView != null
  3817.                 && openPgpView.handleOnActivityResult(requestCode, resultCode,
  3818.                         data)) {
  3819.             return;
  3820.         }
  3821.     }
  3822.  
  3823.    
  3824.    
  3825.     public class DrawerItemClickListener implements
  3826.             ListView.OnItemClickListener {
  3827.         @Override
  3828.         public void onItemClick(AdapterView<?> parent, View view, int position,
  3829.                 long id) {
  3830.             selectItem(position);
  3831.         }
  3832.     }
  3833.  
  3834.     private void selectItem(int position) {
  3835.  
  3836.         if (position < mAdapter_Accounts.getCount() + 1 && position > 0) {
  3837.  
  3838.             progress = ProgressDialog.show(this, "", "", true);
  3839.  
  3840.             goBack();
  3841.  
  3842.             BaseAccount account = (BaseAccount) getListView()
  3843.                     .getItemAtPosition(position);
  3844.             onOpenAccount(account);
  3845.  
  3846.             recreate();
  3847.  
  3848.             progress.dismiss();
  3849.  
  3850.         }
  3851.  
  3852.         if (position > mAdapter_Accounts.getCount() + 1) {
  3853.  
  3854.             progress = ProgressDialog.show(this, "", "", true);
  3855.  
  3856.             goBack();
  3857.  
  3858.             onOpenFolder(((FolderInfoHolder) mAdapter.getItem(position
  3859.                     - (mAdapter_Accounts.getCount() + 2))).name);
  3860.  
  3861.             Log.d("Folder Click Listener", "clicked");
  3862.  
  3863.             progress.dismiss();
  3864.  
  3865.         }
  3866.  
  3867.         mListView.setItemChecked(position, true);
  3868.  
  3869.         mDrawerLayout.closeDrawer(mDrawerLinear);
  3870.     }
  3871.  
  3872.     protected void onUpdateData(int reason) {
  3873.         Log.d(TAG, "onUpdateData(" + reason + ")");
  3874.         doRefresh();
  3875.     }
  3876.  
  3877.     private void alert_logout() {
  3878.  
  3879.         SharedPreferences name = getSharedPreferences("Login_info",
  3880.                 Context.MODE_PRIVATE);
  3881.  
  3882.         String person = name.getString("name", "");
  3883.  
  3884.         {
  3885.             AlertDialog.Builder builder = new AlertDialog.Builder(this);
  3886.             builder.setMessage(
  3887.                     "Are You Sure You Want to Logout " + person
  3888.                             + "? This Will Delete All Your Data.").setTitle(
  3889.                     "Logout");
  3890.  
  3891.             builder.setPositiveButton("Yes",
  3892.                     new DialogInterface.OnClickListener() {
  3893.                         @Override
  3894.                         public void onClick(DialogInterface dialog, int id) {
  3895.  
  3896.                             clearApplicationData();
  3897.  
  3898.                             android.os.Process.killProcess(android.os.Process
  3899.                                     .myPid());
  3900.  
  3901.                         }
  3902.                     });
  3903.  
  3904.             builder.setNegativeButton("No",
  3905.                     new DialogInterface.OnClickListener() {
  3906.                         @Override
  3907.                         public void onClick(DialogInterface dialog, int id) {
  3908.  
  3909.                             dialog.dismiss();
  3910.  
  3911.                         }
  3912.                     });
  3913.  
  3914.             AlertDialog alertDialog = builder.create();
  3915.  
  3916.             alertDialog.show();
  3917.  
  3918.         }
  3919.  
  3920.     }
  3921.  
  3922.     public void clearApplicationData() {
  3923.         File cache = getCacheDir();
  3924.         File appDir = new File(cache.getParent());
  3925.         if (appDir.exists()) {
  3926.             String[] children = appDir.list();
  3927.             for (String s : children) {
  3928.                 if (!s.equals("lib")) {
  3929.                     deleteDir(new File(appDir, s));
  3930.                     Log.i("TAG",
  3931.                             "**************** File /data/data/APP_PACKAGE/" + s
  3932.                                     + " DELETED *******************");
  3933.                 }
  3934.             }
  3935.         }
  3936.     }
  3937.  
  3938.     public static boolean deleteDir(File dir) {
  3939.         if (dir != null && dir.isDirectory()) {
  3940.             String[] children = dir.list();
  3941.             for (int i = 0; i < children.length; i++) {
  3942.                 boolean success = deleteDir(new File(dir, children[i]));
  3943.                 if (!success) {
  3944.                     return false;
  3945.                 }
  3946.             }
  3947.         }
  3948.  
  3949.         return dir.delete();
  3950.     }
  3951.  
  3952.     @Override
  3953.     public void onDestroy() {
  3954.         super.onDestroy();
  3955.         Log.d(TAG, "onDestroy()");
  3956.         if (contentObserver != null) {
  3957.             getContentResolver().unregisterContentObserver(contentObserver);
  3958.             contentObserver = null;
  3959.         }
  3960.         if (receiver != null) {
  3961.             unregisterReceiver(receiver);
  3962.             receiver = null;
  3963.         }
  3964.     }
  3965.  
  3966.     protected void doRefresh() {
  3967.         Log.d(TAG, "doRefresh()");
  3968.  
  3969.         int countssssss = getUnreadK9Count(this);
  3970.  
  3971.         Log.d(TAG, "" + countssssss + " unread emails");
  3972.  
  3973.     }
  3974.  
  3975.     public static class CursorHandler {
  3976.         private List<Cursor> cursors = new ArrayList<Cursor>();
  3977.  
  3978.         public Cursor add(Cursor c) {
  3979.             if (c != null)
  3980.                 cursors.add(c);
  3981.             return c;
  3982.         }
  3983.  
  3984.         public void closeAll() {
  3985.             for (Cursor c : cursors) {
  3986.                 if (!c.isClosed())
  3987.                     c.close();
  3988.             }
  3989.         }
  3990.     }
  3991.  
  3992.     private static int k9UnreadCount = 0;
  3993.  
  3994.     public static int getUnreadK9Count(Context context) {
  3995.         refreshUnreadK9Count(context);
  3996.  
  3997.         return k9UnreadCount;
  3998.     }
  3999.  
  4000.     private static int getUnreadK9Count(Context context, int accountNumber) {
  4001.         CursorHandler ch = new CursorHandler();
  4002.         try {
  4003.             Cursor cur = ch.add(context.getContentResolver().query(
  4004.                     Uri.parse(k9UnreadUri + "/" + accountNumber + "/"), null,
  4005.                     null, null, null));
  4006.             if (cur != null) {
  4007.                 Log.d(TAG, "k9: " + cur.getCount() + " unread rows returned");
  4008.  
  4009.                 if (cur.getCount() > 0) {
  4010.                     cur.moveToFirst();
  4011.                     int unread = 0;
  4012.                     int nameIndex = cur.getColumnIndex("accountName");
  4013.                     int unreadIndex = cur.getColumnIndex("unread");
  4014.                     do {
  4015.                         String acct = cur.getString(nameIndex);
  4016.                         int unreadForAcct = cur.getInt(unreadIndex);
  4017.                         Log.d(TAG, "k9: " + acct + " - " + unreadForAcct
  4018.                                 + " unread");
  4019.                         unread += unreadForAcct;
  4020.                     } while (cur.moveToNext());
  4021.                     cur.close();
  4022.                     return unread;
  4023.                 }
  4024.             } else {
  4025.                 Log.d(TAG, "Failed to query k9 unread contentprovider.");
  4026.             }
  4027.         } catch (IllegalStateException e) {
  4028.             Log.d(TAG, "k-9 unread uri unknown.");
  4029.         }
  4030.         return 0;
  4031.     }
  4032.  
  4033.     public static void refreshUnreadK9Count(Context context) {
  4034.         int accounts = getK9AccountCount(context);
  4035.         if (accounts > 0) {
  4036.             int countssssss = 0;
  4037.             for (int acct = 0; acct < accounts; ++acct) {
  4038.                 countssssss += getUnreadK9Count(context, acct);
  4039.             }
  4040.             k9UnreadCount = countssssss;
  4041.         }
  4042.     }
  4043.  
  4044.     public static int getK9AccountCount(Context context) {
  4045.         CursorHandler ch = new CursorHandler();
  4046.         try {
  4047.             Cursor cur = ch.add(context.getContentResolver().query(
  4048.                     k9AccountsUri, null, null, null, null));
  4049.             if (cur != null) {
  4050.                 // if (Preferences.logging) Log.d(MetaWatch.TAG,
  4051.                 // "k9: "+cur.getCount()+ " account rows returned");
  4052.  
  4053.                 int count = cur.getCount();
  4054.  
  4055.                 return count;
  4056.             } else {
  4057.                 // if (Preferences.logging) Log.d(MetaWatch.TAG,
  4058.                 // "Failed to query k9 unread contentprovider.");
  4059.             }
  4060.         } catch (IllegalStateException e) {
  4061.             // if (Preferences.logging) Log.d(MetaWatch.TAG,
  4062.             // "k-9 accounts uri unknown.");
  4063.         } catch (java.lang.SecurityException e) {
  4064.             // if (Preferences.logging) Log.d(MetaWatch.TAG,
  4065.             // "Permissions failure accessing k-9 databases");
  4066.         } finally {
  4067.             ch.closeAll();
  4068.         }
  4069.         return 0;
  4070.  
  4071.     }
  4072.  
  4073.     /**
  4074.      * Create a new {@link AccountsAdapter} instance and assign it to the
  4075.      * {@link ListView}.
  4076.      *
  4077.      * @param realAccounts
  4078.      *            An array of accounts to display.
  4079.      */
  4080.     public void populateListView(Account[] realAccounts) {
  4081.         List<BaseAccount> accounts = new ArrayList<BaseAccount>();
  4082.  
  4083.         if (displaySpecialAccounts() && !K9.isHideSpecialAccounts()) {
  4084.             BaseAccount unifiedInboxAccount = SearchAccount
  4085.                     .createUnifiedInboxAccount(this);
  4086.             BaseAccount allMessagesAccount = SearchAccount
  4087.                     .createAllMessagesAccount(this);
  4088.  
  4089.             accounts.add(unifiedInboxAccount);
  4090.             accounts.add(allMessagesAccount);
  4091.         }
  4092.  
  4093.         accounts.addAll(Arrays.asList(realAccounts));
  4094.         AccountsAdapter adapter = new AccountsAdapter(accounts);
  4095.  
  4096.         getListView().invalidate();
  4097.  
  4098.         mergeadapter.addView(header_inbox, true);
  4099.  
  4100.         mergeadapter.addAdapter(adapter);
  4101.  
  4102.         mergeadapter.addView(header_folders, true);
  4103.  
  4104.         mergeadapter.addAdapter(mAdapter);
  4105.  
  4106.         getListView().setAdapter(mergeadapter);
  4107.  
  4108.     }
  4109.  
  4110.     /**
  4111.      * Implementing decide whether or not to display special accounts in the
  4112.      * list.
  4113.      *
  4114.      * @return {@code true}, if special accounts should be listed. {@code false}
  4115.      *         , otherwise.
  4116.      */
  4117.     protected boolean displaySpecialAccounts() {
  4118.         return true;
  4119.     }
  4120.  
  4121.     /**
  4122.      * This method will be called when an account was selected.
  4123.      *
  4124.      * @param account
  4125.      *            The account the user selected.
  4126.      */
  4127.     protected void onAccountSelected(BaseAccount account) {
  4128.     }
  4129.  
  4130.     /**
  4131.      * Load accounts in a background thread
  4132.      */
  4133.     class LoadAccounts extends AsyncTask<Void, Void, Account[]> {
  4134.         @Override
  4135.         protected Account[] doInBackground(Void... params) {
  4136.             Account[] accounts = Preferences.getPreferences(
  4137.                     getApplicationContext()).getAccounts();
  4138.             return accounts;
  4139.         }
  4140.  
  4141.         @Override
  4142.         protected void onPostExecute(Account[] accounts) {
  4143.             populateListView(accounts);
  4144.         }
  4145.     }
  4146.  
  4147.     public class AccountsAdapter extends ArrayAdapter<BaseAccount> {
  4148.         public AccountsAdapter(List<BaseAccount> accounts) {
  4149.             super(MessageList.this, 0, accounts);
  4150.         }
  4151.  
  4152.         @Override
  4153.         public View getView(int position, View convertView, ViewGroup parent) {
  4154.  
  4155.             final BaseAccount account = getItem(position);
  4156.  
  4157.             final View view;
  4158.             if (convertView != null) {
  4159.                 view = convertView;
  4160.             } else {
  4161.                 view = getLayoutInflater().inflate(R.layout.accounts_item,
  4162.                         parent, false);
  4163.                 view.findViewById(R.id.active_icons);
  4164.                 view.findViewById(R.id.folders);
  4165.             }
  4166.  
  4167.             AccountViewHolder holder = (AccountViewHolder) view.getTag();
  4168.             if (holder == null) {
  4169.                 holder = new AccountViewHolder();
  4170.                 holder.description = (TextView) view
  4171.                         .findViewById(R.id.description);
  4172.                 holder.email = (TextView) view.findViewById(R.id.email);
  4173.                 holder.description = (TextView) view
  4174.                         .findViewById(R.id.description);
  4175.                 holder.email = (TextView) view.findViewById(R.id.email);
  4176.                 holder.newMessageCount = (TextView) view
  4177.                         .findViewById(R.id.new_message_count);
  4178.                 holder.flaggedMessageCount = (TextView) view
  4179.                         .findViewById(R.id.flagged_message_count);
  4180.                 holder.newMessageCountWrapper = view
  4181.                         .findViewById(R.id.new_message_count_wrapper);
  4182.                 holder.flaggedMessageCountWrapper = view
  4183.                         .findViewById(R.id.flagged_message_count_wrapper);
  4184.                 holder.newMessageCountIcon = view
  4185.                         .findViewById(R.id.new_message_count_icon);
  4186.                 holder.flaggedMessageCountIcon = view
  4187.                         .findViewById(R.id.flagged_message_count_icon);
  4188.                 holder.activeIcons = (RelativeLayout) view
  4189.                         .findViewById(R.id.active_icons);
  4190.                 holder.chip = view.findViewById(R.id.chip);
  4191.                 holder.folders = (ImageButton) view.findViewById(R.id.folders);
  4192.                 holder.accountsItemLayout = (LinearLayout) view
  4193.                         .findViewById(R.id.accounts_item_layout);
  4194.  
  4195.                 view.setTag(holder);
  4196.             }
  4197.  
  4198.             String description = account.getDescription();
  4199.             if (account.getEmail().equals(description)) {
  4200.                 holder.email.setVisibility(View.GONE);
  4201.             } else {
  4202.                 holder.email.setVisibility(View.VISIBLE);
  4203.                 holder.email.setText(account.getEmail());
  4204.             }
  4205.  
  4206.             if (description == null || description.isEmpty()) {
  4207.                 description = account.getEmail();
  4208.             }
  4209.  
  4210.             holder.description.setText(description);
  4211.  
  4212.             if (account instanceof Account) {
  4213.                 Account realAccount = (Account) account;
  4214.  
  4215.             } else {
  4216.  
  4217.             }
  4218.  
  4219.             mFontSizes.setViewTextSize(holder.description,
  4220.                     mFontSizes.getAccountName());
  4221.             mFontSizes.setViewTextSize(holder.email,
  4222.                     mFontSizes.getAccountDescription());
  4223.  
  4224.             AccountStats stats = accountStats.get(account.getUuid());
  4225.  
  4226.             if (stats != null && account instanceof Account && stats.size >= 0) {
  4227.                 holder.email.setText(SizeFormatter.formatSize(MessageList.this,
  4228.                         stats.size));
  4229.                 holder.email.setVisibility(View.VISIBLE);
  4230.             } else {
  4231.                 if (account.getEmail().equals(account.getDescription())) {
  4232.                     holder.email.setVisibility(View.GONE);
  4233.                 } else {
  4234.                     holder.email.setVisibility(View.VISIBLE);
  4235.                     holder.email.setText(account.getEmail());
  4236.                 }
  4237.             }
  4238.  
  4239.             description = account.getDescription();
  4240.             if (description == null || description.isEmpty()) {
  4241.                 description = account.getEmail();
  4242.             }
  4243.  
  4244.             holder.description.setText(description);
  4245.  
  4246.             Integer unreadMessageCount = null;
  4247.             if (stats != null) {
  4248.                 unreadMessageCount = stats.unreadMessageCount;
  4249.                 holder.newMessageCount.setText(Integer
  4250.                         .toString(unreadMessageCount));
  4251.                 holder.newMessageCountWrapper
  4252.                         .setVisibility(unreadMessageCount > 0 ? View.VISIBLE
  4253.                                 : View.GONE);
  4254.  
  4255.                 holder.flaggedMessageCount.setText(Integer
  4256.                         .toString(stats.flaggedMessageCount));
  4257.                 holder.flaggedMessageCountWrapper
  4258.                         .setVisibility(K9.messageListStars()
  4259.                                 && stats.flaggedMessageCount > 0 ? View.VISIBLE
  4260.                                 : View.GONE);
  4261.  
  4262.                 holder.flaggedMessageCountWrapper
  4263.                         .setOnClickListener(createFlaggedSearchListener(account));
  4264.                 holder.newMessageCountWrapper
  4265.                         .setOnClickListener(createUnreadSearchListener(account));
  4266.  
  4267.                 holder.activeIcons.setOnClickListener(new OnClickListener() {
  4268.                     @Override
  4269.                     public void onClick(View v) {
  4270.                         Toast toast = Toast.makeText(getApplication(),
  4271.                                 getString(R.string.tap_hint),
  4272.                                 Toast.LENGTH_SHORT);
  4273.                         toast.show();
  4274.                     }
  4275.                 });
  4276.  
  4277.             } else {
  4278.                 holder.newMessageCountWrapper.setVisibility(View.GONE);
  4279.                 holder.flaggedMessageCountWrapper.setVisibility(View.GONE);
  4280.             }
  4281.             if (account instanceof Account) {
  4282.                 Account realAccount = (Account) account;
  4283.  
  4284.                 holder.flaggedMessageCountIcon
  4285.                         .setBackgroundDrawable(realAccount.generateColorChip(
  4286.                                 false, false, false, false, true).drawable());
  4287.                 holder.newMessageCountIcon.setBackgroundDrawable(realAccount
  4288.                         .generateColorChip(false, false, false, false, false)
  4289.                         .drawable());
  4290.  
  4291.             } else {
  4292.  
  4293.                 holder.newMessageCountIcon.setBackgroundDrawable(new ColorChip(
  4294.                         0xff999999, false, ColorChip.CIRCULAR).drawable());
  4295.                 holder.flaggedMessageCountIcon
  4296.                         .setBackgroundDrawable(new ColorChip(0xff999999, false,
  4297.                                 ColorChip.STAR).drawable());
  4298.             }
  4299.  
  4300.             mFontSizes.setViewTextSize(holder.description,
  4301.                     mFontSizes.getAccountName());
  4302.             mFontSizes.setViewTextSize(holder.email,
  4303.                     mFontSizes.getAccountDescription());
  4304.  
  4305.             if (account instanceof SearchAccount) {
  4306.                 holder.folders.setVisibility(View.GONE);
  4307.             } else {
  4308.                 holder.folders.setVisibility(View.VISIBLE);
  4309.                 holder.folders.setOnClickListener(new OnClickListener() {
  4310.                     @Override
  4311.                     public void onClick(View v) {
  4312.  
  4313.                         Log.d("clicked_folder1", "clicked");
  4314.  
  4315.                         FolderList.actionHandleAccount(MessageList.this,
  4316.                                 (Account) account);
  4317.  
  4318.                     }
  4319.                 });
  4320.             }
  4321.  
  4322.             if (account instanceof Account) {
  4323.                 Account realAccount = (Account) account;
  4324.                 holder.chip.setBackgroundColor(realAccount.getChipColor());
  4325.             } else {
  4326.                 holder.chip.setBackgroundColor(0xff999999);
  4327.             }
  4328.  
  4329.             holder.chip.getBackground().setAlpha(255);
  4330.  
  4331.             return view;
  4332.         }
  4333.  
  4334.         private OnClickListener createFlaggedSearchListener(BaseAccount account) {
  4335.             String searchTitle = getString(R.string.search_title,
  4336.                     account.getDescription(),
  4337.                     getString(R.string.flagged_modifier));
  4338.  
  4339.             Log.d("clicked_folder2", "clicked");
  4340.  
  4341.             LocalSearch search;
  4342.             if (account instanceof SearchAccount) {
  4343.                 search = ((SearchAccount) account).getRelatedSearch().clone();
  4344.                 search.setName(searchTitle);
  4345.             } else {
  4346.                 search = new LocalSearch(searchTitle);
  4347.                 search.addAccountUuid(account.getUuid());
  4348.  
  4349.                 Account realAccount = (Account) account;
  4350.                 realAccount.excludeSpecialFolders(search);
  4351.                 realAccount.limitToDisplayableFolders(search);
  4352.             }
  4353.  
  4354.             search.and(Searchfield.FLAGGED, "1", Attribute.EQUALS);
  4355.  
  4356.             return new AccountClickListener(search);
  4357.         }
  4358.  
  4359.         private OnClickListener createUnreadSearchListener(BaseAccount account) {
  4360.             LocalSearch search = Accounts.createUnreadSearch(MessageList.this,
  4361.                     account);
  4362.             return new AccountClickListener(search);
  4363.         }
  4364.  
  4365.         class AccountViewHolder {
  4366.             public TextView description;
  4367.             public TextView email;
  4368.             public TextView newMessageCount;
  4369.             public TextView flaggedMessageCount;
  4370.             public View newMessageCountIcon;
  4371.             public View flaggedMessageCountIcon;
  4372.             public View newMessageCountWrapper;
  4373.             public View flaggedMessageCountWrapper;
  4374.             public View chip;
  4375.             public RelativeLayout activeIcons;
  4376.  
  4377.             public ImageButton folders;
  4378.             public LinearLayout accountsItemLayout;
  4379.         }
  4380.     }
  4381.  
  4382.     private class AccountClickListener implements OnClickListener {
  4383.  
  4384.         final LocalSearch search;
  4385.  
  4386.         AccountClickListener(LocalSearch search) {
  4387.             this.search = search;
  4388.         }
  4389.  
  4390.         @Override
  4391.         public void onClick(View v) {
  4392.             MessageList.actionDisplaySearch(MessageList.this, search, true,
  4393.                     false);
  4394.             Log.d("clicked_folder3", "clicked");
  4395.         }
  4396.  
  4397.     }
  4398.  
  4399.     private BaseAccount[] accounts = new BaseAccount[0];
  4400.  
  4401.     private enum ACCOUNT_LOCATION {
  4402.         TOP, MIDDLE, BOTTOM;
  4403.     }
  4404.  
  4405.     private EnumSet<ACCOUNT_LOCATION> accountLocation(BaseAccount account) {
  4406.         EnumSet<ACCOUNT_LOCATION> accountLocation = EnumSet
  4407.                 .of(ACCOUNT_LOCATION.MIDDLE);
  4408.         if (accounts.length > 0) {
  4409.             if (accounts[0].equals(account)) {
  4410.                 accountLocation.remove(ACCOUNT_LOCATION.MIDDLE);
  4411.                 accountLocation.add(ACCOUNT_LOCATION.TOP);
  4412.             }
  4413.             if (accounts[accounts.length - 1].equals(account)) {
  4414.                 accountLocation.remove(ACCOUNT_LOCATION.MIDDLE);
  4415.                 accountLocation.add(ACCOUNT_LOCATION.BOTTOM);
  4416.             }
  4417.         }
  4418.         return accountLocation;
  4419.     }
  4420.  
  4421.     private void onAddNewAccount() {
  4422.         AccountSetupBasics.actionNewAccount(this);
  4423.     }
  4424.  
  4425.     /*
  4426.      * This method is called with 'null' for the argument 'account' if all
  4427.      * accounts are to be checked. This is handled accordingly in
  4428.      * MessagingController.checkMail().
  4429.      */
  4430.     private void onCheckMail(Account account) {
  4431.         MessagingController.getInstance(getApplication()).checkMail(this,
  4432.                 account, true, true, null);
  4433.         if (account == null) {
  4434.             MessagingController.getInstance(getApplication())
  4435.                     .sendPendingMessages(null);
  4436.         } else {
  4437.             MessagingController.getInstance(getApplication())
  4438.                     .sendPendingMessages(account, null);
  4439.         }
  4440.  
  4441.     }
  4442.  
  4443.     private void onClearCommands(Account account) {
  4444.         MessagingController.getInstance(getApplication()).clearAllPending(
  4445.                 account);
  4446.     }
  4447.  
  4448.     private void onCompose() {
  4449.         Account defaultAccount = Preferences.getPreferences(this)
  4450.                 .getDefaultAccount();
  4451.         if (defaultAccount != null) {
  4452.             MessageCompose.actionCompose(this, defaultAccount);
  4453.         } else {
  4454.             onAddNewAccount();
  4455.         }
  4456.     }
  4457.  
  4458.     /**
  4459.      * Show that account's inbox or folder-list or return false if the account
  4460.      * is not available.
  4461.      *
  4462.      * @param account
  4463.      *            the account to open ({@link SearchAccount} or {@link Account})
  4464.      * @return false if unsuccessfull
  4465.      */
  4466.     boolean onOpenAccount(BaseAccount account) {
  4467.         if (account instanceof SearchAccount) {
  4468.             SearchAccount searchAccount = (SearchAccount) account;
  4469.             MessageList.actionDisplaySearch(this,
  4470.                     searchAccount.getRelatedSearch(), false, false);
  4471.         } else {
  4472.             Account realAccount = (Account) account;
  4473.             if (!realAccount.isEnabled()) {
  4474.                 onActivateAccount(realAccount);
  4475.                 return false;
  4476.             } else if (!realAccount.isAvailable(this)) {
  4477.                 String toastText = getString(R.string.account_unavailable,
  4478.                         account.getDescription());
  4479.                 Toast toast = Toast.makeText(getApplication(), toastText,
  4480.                         Toast.LENGTH_SHORT);
  4481.                 toast.show();
  4482.  
  4483.                 Log.i(K9.LOG_TAG,
  4484.                         "refusing to open account that is not available");
  4485.                 return false;
  4486.             }
  4487.             if (K9.FOLDER_NONE.equals(realAccount.getAutoExpandFolderName())) {
  4488.                 FolderList.actionHandleAccount(this, realAccount);
  4489.             } else {
  4490.                 LocalSearch search = new LocalSearch(
  4491.                         realAccount.getAutoExpandFolderName());
  4492.                 search.addAllowedFolder(realAccount.getAutoExpandFolderName());
  4493.                 search.addAccountUuid(realAccount.getUuid());
  4494.                 MessageList.actionDisplaySearch(this, search, false, true);
  4495.             }
  4496.         }
  4497.         return true;
  4498.     }
  4499.  
  4500.     void onActivateAccount(Account account) {
  4501.         List<Account> disabledAccounts = new ArrayList<Account>();
  4502.         disabledAccounts.add(account);
  4503.         promptForServerPasswords(disabledAccounts);
  4504.     }
  4505.  
  4506.     /**
  4507.      * Ask the user to enter the server passwords for disabled accounts.
  4508.      *
  4509.      * @param disabledAccounts
  4510.      *            A non-empty list of {@link Account}s to ask the user for
  4511.      *            passwords. Never {@code null}.
  4512.      *            <p>
  4513.      *            <strong>Note:</strong> Calling this method will modify the
  4514.      *            supplied list.
  4515.      *            </p>
  4516.      */
  4517.     void promptForServerPasswords(final List<Account> disabledAccounts) {
  4518.         Account account = disabledAccounts.remove(0);
  4519.         PasswordPromptDialog dialog = new PasswordPromptDialog(account,
  4520.                 disabledAccounts);
  4521.         setNonConfigurationInstance(dialog);
  4522.         dialog.show(this);
  4523.     }
  4524.  
  4525.     /**
  4526.      * Ask the user for the incoming/outgoing server passwords.
  4527.      */
  4528.     private static class PasswordPromptDialog implements
  4529.             NonConfigurationInstance, TextWatcher {
  4530.         private AlertDialog mDialog;
  4531.         private EditText mIncomingPasswordView;
  4532.         private EditText mOutgoingPasswordView;
  4533.         private CheckBox mUseIncomingView;
  4534.  
  4535.         private Account mAccount;
  4536.         private List<Account> mRemainingAccounts;
  4537.         private String mIncomingPassword;
  4538.         private String mOutgoingPassword;
  4539.         private boolean mUseIncoming;
  4540.  
  4541.         /**
  4542.          * Constructor
  4543.          *
  4544.          * @param account
  4545.          *            The {@link Account} to ask the server passwords for. Never
  4546.          *            {@code null}.
  4547.          * @param accounts
  4548.          *            The (possibly empty) list of remaining accounts to ask
  4549.          *            passwords for. Never {@code null}.
  4550.          */
  4551.         PasswordPromptDialog(Account account, List<Account> accounts) {
  4552.             mAccount = account;
  4553.             mRemainingAccounts = accounts;
  4554.         }
  4555.  
  4556.         @Override
  4557.         public void restore(Activity activity) {
  4558.             show((Accounts) activity, true);
  4559.         }
  4560.  
  4561.         @Override
  4562.         public boolean retain() {
  4563.             if (mDialog != null) {
  4564.                 // Retain entered passwords and checkbox state
  4565.                 mIncomingPassword = mIncomingPasswordView.getText().toString();
  4566.                 if (mOutgoingPasswordView != null) {
  4567.                     mOutgoingPassword = mOutgoingPasswordView.getText()
  4568.                             .toString();
  4569.                     mUseIncoming = mUseIncomingView.isChecked();
  4570.                 }
  4571.  
  4572.                 // Dismiss dialog
  4573.                 mDialog.dismiss();
  4574.  
  4575.                 // Clear all references to UI objects
  4576.                 mDialog = null;
  4577.                 mIncomingPasswordView = null;
  4578.                 mOutgoingPasswordView = null;
  4579.                 mUseIncomingView = null;
  4580.                 return true;
  4581.             }
  4582.             return false;
  4583.         }
  4584.  
  4585.         public void show(MessageList messageList) {
  4586.             show(messageList);
  4587.         }
  4588.  
  4589.         private void show(final Accounts activity, boolean restore) {
  4590.             ServerSettings incoming = Store.decodeStoreUri(mAccount
  4591.                     .getStoreUri());
  4592.             ServerSettings outgoing = Transport.decodeTransportUri(mAccount
  4593.                     .getTransportUri());
  4594.  
  4595.             // Don't ask for the password to the outgoing server for WebDAV
  4596.             // accounts, because
  4597.             // incoming and outgoing servers are identical for this account
  4598.             // type.
  4599.             boolean configureOutgoingServer = !WebDavStore.STORE_TYPE
  4600.                     .equals(outgoing.type);
  4601.  
  4602.             // Create a ScrollView that will be used as container for the whole
  4603.             // layout
  4604.             final ScrollView scrollView = new ScrollView(activity);
  4605.  
  4606.             // Create the dialog
  4607.             final AlertDialog.Builder builder = new AlertDialog.Builder(
  4608.                     activity);
  4609.             builder.setTitle(activity
  4610.                     .getString(R.string.settings_import_activate_account_header));
  4611.             builder.setView(scrollView);
  4612.             builder.setPositiveButton(activity.getString(R.string.okay_action),
  4613.                     new DialogInterface.OnClickListener() {
  4614.                         @Override
  4615.                         public void onClick(DialogInterface dialog, int which) {
  4616.                             String incomingPassword = mIncomingPasswordView
  4617.                                     .getText().toString();
  4618.                             String outgoingPassword = null;
  4619.                             if (mOutgoingPasswordView != null) {
  4620.                                 outgoingPassword = (mUseIncomingView
  4621.                                         .isChecked()) ? incomingPassword
  4622.                                         : mOutgoingPasswordView.getText()
  4623.                                                 .toString();
  4624.                             }
  4625.  
  4626.                             dialog.dismiss();
  4627.  
  4628.                             // Set the server passwords in the background
  4629.                             SetPasswordsAsyncTask asyncTask = new SetPasswordsAsyncTask(
  4630.                                     activity, mAccount, incomingPassword,
  4631.                                     outgoingPassword, mRemainingAccounts);
  4632.                             activity.setNonConfigurationInstance(asyncTask);
  4633.                             asyncTask.execute();
  4634.                         }
  4635.                     });
  4636.             builder.setNegativeButton(
  4637.                     activity.getString(R.string.cancel_action),
  4638.                     new DialogInterface.OnClickListener() {
  4639.                         @Override
  4640.                         public void onClick(DialogInterface dialog, int which) {
  4641.                             dialog.dismiss();
  4642.                             activity.setNonConfigurationInstance(null);
  4643.                         }
  4644.                     });
  4645.             mDialog = builder.create();
  4646.  
  4647.             // Use the dialog's layout inflater so its theme is used (and not
  4648.             // the activity's theme).
  4649.             View layout = mDialog.getLayoutInflater().inflate(
  4650.                     R.layout.accounts_password_prompt, null);
  4651.  
  4652.             // Set the intro text that tells the user what to do
  4653.             TextView intro = (TextView) layout
  4654.                     .findViewById(R.id.password_prompt_intro);
  4655.             String serverPasswords = activity.getResources().getQuantityString(
  4656.                     R.plurals.settings_import_server_passwords,
  4657.                     (configureOutgoingServer) ? 2 : 1);
  4658.             intro.setText(activity.getString(
  4659.                     R.string.settings_import_activate_account_intro,
  4660.                     mAccount.getDescription(), serverPasswords));
  4661.  
  4662.             // Display the hostname of the incoming server
  4663.             TextView incomingText = (TextView) layout
  4664.                     .findViewById(R.id.password_prompt_incoming_server);
  4665.             incomingText.setText(activity.getString(
  4666.                     R.string.settings_import_incoming_server, incoming.host));
  4667.  
  4668.             mIncomingPasswordView = (EditText) layout
  4669.                     .findViewById(R.id.incoming_server_password);
  4670.             mIncomingPasswordView.addTextChangedListener(this);
  4671.  
  4672.             if (configureOutgoingServer) {
  4673.                 // Display the hostname of the outgoing server
  4674.                 TextView outgoingText = (TextView) layout
  4675.                         .findViewById(R.id.password_prompt_outgoing_server);
  4676.                 outgoingText.setText(activity
  4677.                         .getString(R.string.settings_import_outgoing_server,
  4678.                                 outgoing.host));
  4679.  
  4680.                 mOutgoingPasswordView = (EditText) layout
  4681.                         .findViewById(R.id.outgoing_server_password);
  4682.                 mOutgoingPasswordView.addTextChangedListener(this);
  4683.  
  4684.                 mUseIncomingView = (CheckBox) layout
  4685.                         .findViewById(R.id.use_incoming_server_password);
  4686.                 mUseIncomingView.setChecked(true);
  4687.                 mUseIncomingView
  4688.                         .setOnCheckedChangeListener(new OnCheckedChangeListener() {
  4689.                             @Override
  4690.                             public void onCheckedChanged(
  4691.                                     CompoundButton buttonView, boolean isChecked) {
  4692.                                 if (isChecked) {
  4693.                                     mOutgoingPasswordView.setText(null);
  4694.                                     mOutgoingPasswordView.setEnabled(false);
  4695.                                 } else {
  4696.                                     mOutgoingPasswordView
  4697.                                             .setText(mIncomingPasswordView
  4698.                                                     .getText());
  4699.                                     mOutgoingPasswordView.setEnabled(true);
  4700.                                 }
  4701.                             }
  4702.                         });
  4703.             } else {
  4704.                 layout.findViewById(R.id.outgoing_server_prompt).setVisibility(
  4705.                         View.GONE);
  4706.             }
  4707.  
  4708.             // Add the layout to the ScrollView
  4709.             scrollView.addView(layout);
  4710.  
  4711.             // Show the dialog
  4712.             mDialog.show();
  4713.  
  4714.             // Restore the contents of the password boxes and the checkbox (if
  4715.             // the dialog was
  4716.             // retained during a configuration change).
  4717.             if (restore) {
  4718.                 mIncomingPasswordView.setText(mIncomingPassword);
  4719.                 if (configureOutgoingServer) {
  4720.                     mOutgoingPasswordView.setText(mOutgoingPassword);
  4721.                     mUseIncomingView.setChecked(mUseIncoming);
  4722.                 }
  4723.             } else {
  4724.                 // Trigger afterTextChanged() being called
  4725.                 // Work around this bug:
  4726.                 // https://code.google.com/p/android/issues/detail?id=6360
  4727.                 mIncomingPasswordView.setText(mIncomingPasswordView.getText());
  4728.             }
  4729.         }
  4730.  
  4731.         @Override
  4732.         public void afterTextChanged(Editable arg0) {
  4733.             boolean enable = false;
  4734.             // Is the password box for the incoming server password empty?
  4735.             if (mIncomingPasswordView.getText().length() > 0) {
  4736.                 // Do we need to check the outgoing server password box?
  4737.                 if (mOutgoingPasswordView == null) {
  4738.                     enable = true;
  4739.                 }
  4740.                 // If the checkbox to use the incoming server password is
  4741.                 // checked we need to make
  4742.                 // sure that the password box for the outgoing server isn't
  4743.                 // empty.
  4744.                 else if (mUseIncomingView.isChecked()
  4745.                         || mOutgoingPasswordView.getText().length() > 0) {
  4746.                     enable = true;
  4747.                 }
  4748.             }
  4749.  
  4750.             // Disable "OK" button if the user hasn't specified all necessary
  4751.             // passwords.
  4752.             mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(
  4753.                     enable);
  4754.         }
  4755.  
  4756.         @Override
  4757.         public void beforeTextChanged(CharSequence s, int start, int count,
  4758.                 int after) {
  4759.             // Not used
  4760.         }
  4761.  
  4762.         @Override
  4763.         public void onTextChanged(CharSequence s, int start, int before,
  4764.                 int count) {
  4765.             // Not used
  4766.         }
  4767.     }
  4768.  
  4769.     /**
  4770.      * Set the incoming/outgoing server password in the background.
  4771.      */
  4772.     private static class SetPasswordsAsyncTask extends
  4773.             ExtendedAsyncTask<Void, Void, Void> {
  4774.         private Account mAccount;
  4775.         private String mIncomingPassword;
  4776.         private String mOutgoingPassword;
  4777.         private List<Account> mRemainingAccounts;
  4778.         private Application mApplication;
  4779.  
  4780.         protected SetPasswordsAsyncTask(Activity activity, Account account,
  4781.                 String incomingPassword, String outgoingPassword,
  4782.                 List<Account> remainingAccounts) {
  4783.             super(activity);
  4784.             mAccount = account;
  4785.             mIncomingPassword = incomingPassword;
  4786.             mOutgoingPassword = outgoingPassword;
  4787.             mRemainingAccounts = remainingAccounts;
  4788.             mApplication = mActivity.getApplication();
  4789.         }
  4790.  
  4791.         @Override
  4792.         protected void showProgressDialog() {
  4793.             String title = mActivity
  4794.                     .getString(R.string.settings_import_activate_account_header);
  4795.             int passwordCount = (mOutgoingPassword == null) ? 1 : 2;
  4796.             String message = mActivity.getResources().getQuantityString(
  4797.                     R.plurals.settings_import_setting_passwords, passwordCount);
  4798.             mProgressDialog = ProgressDialog.show(mActivity, title, message,
  4799.                     true);
  4800.         }
  4801.  
  4802.         @Override
  4803.         protected Void doInBackground(Void... params) {
  4804.             try {
  4805.                 // Set incoming server password
  4806.                 String storeUri = mAccount.getStoreUri();
  4807.                 ServerSettings incoming = Store.decodeStoreUri(storeUri);
  4808.                 ServerSettings newIncoming = incoming
  4809.                         .newPassword(mIncomingPassword);
  4810.                 String newStoreUri = Store.createStoreUri(newIncoming);
  4811.                 mAccount.setStoreUri(newStoreUri);
  4812.  
  4813.                 if (mOutgoingPassword != null) {
  4814.                     // Set outgoing server password
  4815.                     String transportUri = mAccount.getTransportUri();
  4816.                     ServerSettings outgoing = Transport
  4817.                             .decodeTransportUri(transportUri);
  4818.                     ServerSettings newOutgoing = outgoing
  4819.                             .newPassword(mOutgoingPassword);
  4820.                     String newTransportUri = Transport
  4821.                             .createTransportUri(newOutgoing);
  4822.                     mAccount.setTransportUri(newTransportUri);
  4823.                 }
  4824.  
  4825.                 // Mark account as enabled
  4826.                 mAccount.setEnabled(true);
  4827.  
  4828.                 // Save the account settings
  4829.                 mAccount.save(Preferences.getPreferences(mContext));
  4830.  
  4831.                 // Start services if necessary
  4832.                 K9.setServicesEnabled(mContext);
  4833.  
  4834.                 // Get list of folders from remote server
  4835.                 MessagingController.getInstance(mApplication).listFolders(
  4836.                         mAccount, true, null);
  4837.             } catch (Exception e) {
  4838.                 Log.e(K9.LOG_TAG,
  4839.                         "Something went while setting account passwords", e);
  4840.             }
  4841.             return null;
  4842.         }
  4843.  
  4844.         @Override
  4845.         protected void onPostExecute(Void result) {
  4846.             Accounts activity = (Accounts) mActivity;
  4847.  
  4848.             // Let the activity know that the background task is complete
  4849.             activity.setNonConfigurationInstance(null);
  4850.  
  4851.             activity.refresh();
  4852.             removeProgressDialog();
  4853.  
  4854.             if (mRemainingAccounts.size() > 0) {
  4855.                 activity.promptForServerPasswords(mRemainingAccounts);
  4856.             }
  4857.         }
  4858.     }
  4859.  
  4860.     void onMove(final Account account, final boolean up) {
  4861.         MoveAccountAsyncTask asyncTask = new MoveAccountAsyncTask(this,
  4862.                 account, up);
  4863.         setNonConfigurationInstance(asyncTask);
  4864.         asyncTask.execute();
  4865.     }
  4866.  
  4867.     @Override
  4868.     public void onItemClick(AdapterView<?> parent, View view, int position,
  4869.             long id) {
  4870.  
  4871.         if (position < mAdapter_Accounts.getCount() + 1) {
  4872.  
  4873.             BaseAccount account = (BaseAccount) parent
  4874.                     .getItemAtPosition(position);
  4875.             onOpenAccount(account);
  4876.  
  4877.         }
  4878.     }
  4879.  
  4880.     private static String[][] USED_LIBRARIES = new String[][] {
  4881.             new String[] { "jutf7", "http://jutf7.sourceforge.net/" },
  4882.             new String[] { "JZlib", "http://www.jcraft.com/jzlib/" },
  4883.             new String[] { "Commons IO", "http://commons.apache.org/io/" },
  4884.             new String[] { "Mime4j", "http://james.apache.org/mime4j/" },
  4885.             new String[] { "HtmlCleaner", "http://htmlcleaner.sourceforge.net/" },
  4886.             new String[] { "Android-PullToRefresh",
  4887.                     "https://github.com/chrisbanes/Android-PullToRefresh" },
  4888.             new String[] { "ckChangeLog",
  4889.                     "https://github.com/cketti/ckChangeLog" },
  4890.             new String[] { "HoloColorPicker",
  4891.                     "https://github.com/LarsWerkman/HoloColorPicker" } };
  4892.  
  4893.     private void onAbout() {
  4894.         String appName = getString(R.string.app_name);
  4895.         int year = Calendar.getInstance().get(Calendar.YEAR);
  4896.         WebView wv = new WebView(this);
  4897.         StringBuilder html = new StringBuilder()
  4898.                 .append("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />")
  4899.                 .append("<img src=\"file:///android_asset/icon.png\" alt=\"")
  4900.                 .append(appName)
  4901.                 .append("\"/>")
  4902.                 .append("<h1>")
  4903.                 .append(String.format(getString(R.string.about_title_fmt),
  4904.                         "<a href=\"" + getString(R.string.app_webpage_url))
  4905.                         + "\">")
  4906.                 .append(appName)
  4907.                 .append("</a>")
  4908.                 .append("</h1><p>")
  4909.                 .append(appName)
  4910.                 .append(" ")
  4911.                 .append(String.format(getString(R.string.debug_version_fmt),
  4912.                         getVersionNumber()))
  4913.                 .append("</p><p>")
  4914.                 .append(String.format(getString(R.string.app_authors_fmt),
  4915.                         getString(R.string.app_authors)))
  4916.                 .append("</p><p>")
  4917.                 .append(String.format(getString(R.string.app_revision_fmt),
  4918.                         "<a href=\"" + getString(R.string.app_revision_url)
  4919.                                 + "\">" + getString(R.string.app_revision_url)
  4920.                                 + "</a>"))
  4921.                 .append("</p><hr/><p>")
  4922.                 .append(String.format(getString(R.string.app_copyright_fmt),
  4923.                         year, year)).append("</p><hr/><p>")
  4924.                 .append(getString(R.string.app_license)).append("</p><hr/><p>");
  4925.  
  4926.         StringBuilder libs = new StringBuilder().append("<ul>");
  4927.         for (String[] library : USED_LIBRARIES) {
  4928.             libs.append("<li><a href=\"").append(library[1]).append("\">")
  4929.                     .append(library[0]).append("</a></li>");
  4930.         }
  4931.         libs.append("</ul>");
  4932.  
  4933.         html.append(
  4934.                 String.format(getString(R.string.app_libraries),
  4935.                         libs.toString()))
  4936.                 .append("</p><hr/><p>")
  4937.                 .append(String
  4938.                         .format(getString(R.string.app_emoji_icons),
  4939.                                 "<div>TypePad \u7d75\u6587\u5b57\u30a2\u30a4\u30b3\u30f3\u753b\u50cf "
  4940.                                         + "(<a href=\"http://typepad.jp/\">Six Apart Ltd</a>) / "
  4941.                                         + "<a href=\"http://creativecommons.org/licenses/by/2.1/jp/\">CC BY 2.1</a></div>"))
  4942.                 .append("</p><hr/><p>")
  4943.                 .append(getString(R.string.app_htmlcleaner_license));
  4944.  
  4945.         wv.loadDataWithBaseURL("file:///android_res/drawable/",
  4946.                 html.toString(), "text/html", "utf-8", null);
  4947.         new AlertDialog.Builder(this)
  4948.                 .setView(wv)
  4949.                 .setCancelable(true)
  4950.                 .setPositiveButton(R.string.okay_action,
  4951.                         new DialogInterface.OnClickListener() {
  4952.                             @Override
  4953.                             public void onClick(DialogInterface d, int c) {
  4954.                                 d.dismiss();
  4955.                             }
  4956.                         })
  4957.                 .setNeutralButton(R.string.changelog_full_title,
  4958.                         new DialogInterface.OnClickListener() {
  4959.                             @Override
  4960.                             public void onClick(DialogInterface d, int c) {
  4961.                                 new ChangeLog(MessageList.this)
  4962.                                         .getFullLogDialog().show();
  4963.                             }
  4964.                         }).show();
  4965.     }
  4966.  
  4967.     /**
  4968.      * Get current version number.
  4969.      *
  4970.      * @return String version
  4971.      */
  4972.     private String getVersionNumber() {
  4973.         String version = "?";
  4974.         try {
  4975.             PackageInfo pi = getPackageManager().getPackageInfo(
  4976.                     getPackageName(), 0);
  4977.             version = pi.versionName;
  4978.         } catch (PackageManager.NameNotFoundException e) {
  4979.             // Log.e(TAG, "Package name not found", e);
  4980.         }
  4981.         return version;
  4982.     }
  4983.  
  4984.     public boolean onItemLongClick(AdapterView<?> parent, View view,
  4985.             int position, long id) {
  4986.         return true;
  4987.     }
  4988.  
  4989.     void onImport() {
  4990.         Intent i = new Intent(Intent.ACTION_GET_CONTENT);
  4991.         i.addCategory(Intent.CATEGORY_OPENABLE);
  4992.         i.setType("*/*");
  4993.  
  4994.         PackageManager packageManager = getPackageManager();
  4995.         List<ResolveInfo> infos = packageManager.queryIntentActivities(i, 0);
  4996.  
  4997.         if (infos.size() > 0) {
  4998.             startActivityForResult(Intent.createChooser(i, null),
  4999.                     ACTIVITY_REQUEST_PICK_SETTINGS_FILE);
  5000.         } else {
  5001.             showDialog(DIALOG_NO_FILE_MANAGER);
  5002.         }
  5003.     }
  5004.  
  5005.     private void onImport(Uri uri) {
  5006.         ListImportContentsAsyncTask asyncTask = new ListImportContentsAsyncTask(
  5007.                 this, uri);
  5008.         setNonConfigurationInstance(asyncTask);
  5009.         asyncTask.execute();
  5010.     }
  5011.  
  5012.     void showSimpleDialog(int headerRes, int messageRes, Object... args) {
  5013.         SimpleDialog dialog = new SimpleDialog(headerRes, messageRes, args);
  5014.         dialog.show(this);
  5015.         setNonConfigurationInstance(dialog);
  5016.     }
  5017.  
  5018.     /**
  5019.      * A simple dialog.
  5020.      */
  5021.     private static class SimpleDialog implements NonConfigurationInstance {
  5022.         private final int mHeaderRes;
  5023.         private final int mMessageRes;
  5024.         private Object[] mArguments;
  5025.         private Dialog mDialog;
  5026.  
  5027.         SimpleDialog(int headerRes, int messageRes, Object... args) {
  5028.             this.mHeaderRes = headerRes;
  5029.             this.mMessageRes = messageRes;
  5030.             this.mArguments = args;
  5031.         }
  5032.  
  5033.         @Override
  5034.         public void restore(Activity activity) {
  5035.             show((MessageList) activity);
  5036.         }
  5037.  
  5038.         @Override
  5039.         public boolean retain() {
  5040.             if (mDialog != null) {
  5041.                 mDialog.dismiss();
  5042.                 mDialog = null;
  5043.                 return true;
  5044.             }
  5045.             return false;
  5046.         }
  5047.  
  5048.         public void show(final MessageList messageList) {
  5049.             final String message = generateMessage(messageList);
  5050.  
  5051.             final AlertDialog.Builder builder = new AlertDialog.Builder(
  5052.                     messageList);
  5053.             builder.setTitle(mHeaderRes);
  5054.             builder.setMessage(message);
  5055.             builder.setPositiveButton(R.string.okay_action,
  5056.                     new DialogInterface.OnClickListener() {
  5057.                         @Override
  5058.                         public void onClick(DialogInterface dialog, int which) {
  5059.                             dialog.dismiss();
  5060.                             messageList.setNonConfigurationInstance(null);
  5061.                             okayAction(messageList);
  5062.                         }
  5063.                     });
  5064.             mDialog = builder.show();
  5065.         }
  5066.  
  5067.         /**
  5068.          * Returns the message the dialog should display.
  5069.          *
  5070.          * @param messageList
  5071.          *            The {@code Activity} this dialog belongs to.
  5072.          *
  5073.          * @return The message the dialog should display
  5074.          */
  5075.         protected String generateMessage(MessageList messageList) {
  5076.             return messageList.getString(mMessageRes, mArguments);
  5077.         }
  5078.  
  5079.         /**
  5080.          * This method is called after the "OK" button was pressed.
  5081.          *
  5082.          * @param messageList
  5083.          *            The {@code Activity} this dialog belongs to.
  5084.          */
  5085.         protected void okayAction(MessageList messageList) {
  5086.             // Do nothing
  5087.         }
  5088.     }
  5089.  
  5090.     /**
  5091.      * Shows a dialog that displays how many accounts were successfully
  5092.      * imported.
  5093.      *
  5094.      * @param importResults
  5095.      *            The {@link ImportResults} instance returned by the
  5096.      *            {@link SettingsImporter}.
  5097.      * @param filename
  5098.      *            The name of the settings file that was imported.
  5099.      */
  5100.     void showAccountsImportedDialog(ImportResults importResults, String filename) {
  5101.         AccountsImportedDialog dialog = new AccountsImportedDialog(
  5102.                 importResults, filename);
  5103.         dialog.show(MessageList.this);
  5104.         setNonConfigurationInstance(dialog);
  5105.     }
  5106.  
  5107.     /**
  5108.      * A dialog that displays how many accounts were successfully imported.
  5109.      */
  5110.     private static class AccountsImportedDialog extends SimpleDialog {
  5111.         private ImportResults mImportResults;
  5112.         private String mFilename;
  5113.  
  5114.         AccountsImportedDialog(ImportResults importResults, String filename) {
  5115.             super(R.string.settings_import_success_header,
  5116.                     R.string.settings_import_success);
  5117.             mImportResults = importResults;
  5118.             mFilename = filename;
  5119.         }
  5120.  
  5121.         @Override
  5122.         protected String generateMessage(MessageList activity) {
  5123.             // TODO: display names of imported accounts (name from file *and*
  5124.             // possibly new name)
  5125.  
  5126.             int imported = mImportResults.importedAccounts.size();
  5127.             String accounts = activity.getResources().getQuantityString(
  5128.                     R.plurals.settings_import_accounts, imported, imported);
  5129.             return activity.getString(R.string.settings_import_success,
  5130.                     accounts, mFilename);
  5131.         }
  5132.  
  5133.         @Override
  5134.         protected void okayAction(MessageList activity) {
  5135.             Context context = activity.getApplicationContext();
  5136.             Preferences preferences = Preferences.getPreferences(context);
  5137.             List<Account> disabledAccounts = new ArrayList<Account>();
  5138.             for (AccountDescriptionPair accountPair : mImportResults.importedAccounts) {
  5139.                 Account account = preferences
  5140.                         .getAccount(accountPair.imported.uuid);
  5141.                 if (account != null && !account.isEnabled()) {
  5142.                     disabledAccounts.add(account);
  5143.                 }
  5144.             }
  5145.             if (disabledAccounts.size() > 0) {
  5146.                 activity.promptForServerPasswords(disabledAccounts);
  5147.             } else {
  5148.                 activity.setNonConfigurationInstance(null);
  5149.             }
  5150.         }
  5151.     }
  5152.  
  5153.     /**
  5154.      * Display a dialog that lets the user select which accounts to import from
  5155.      * the settings file.
  5156.      *
  5157.      * @param importContents
  5158.      *            The {@link ImportContents} instance returned by
  5159.      *            {@link SettingsImporter#getImportStreamContents(InputStream)}
  5160.      * @param uri
  5161.      *            The (content) URI of the settings file.
  5162.      */
  5163.     void showImportSelectionDialog(ImportContents importContents, Uri uri) {
  5164.         ImportSelectionDialog dialog = new ImportSelectionDialog(
  5165.                 importContents, uri);
  5166.         dialog.show(this);
  5167.         setNonConfigurationInstance(dialog);
  5168.     }
  5169.  
  5170.     /**
  5171.      * A dialog that lets the user select which accounts to import from the
  5172.      * settings file.
  5173.      */
  5174.     private static class ImportSelectionDialog implements
  5175.             NonConfigurationInstance {
  5176.         private ImportContents mImportContents;
  5177.         private Uri mUri;
  5178.         private AlertDialog mDialog;
  5179.  
  5180.         private SparseBooleanArray mSelection;
  5181.  
  5182.         ImportSelectionDialog(ImportContents importContents, Uri uri) {
  5183.             mImportContents = importContents;
  5184.             mUri = uri;
  5185.         }
  5186.  
  5187.         @Override
  5188.         public void restore(Activity activity) {
  5189.             show((MessageList) activity, mSelection);
  5190.         }
  5191.  
  5192.         @Override
  5193.         public boolean retain() {
  5194.  
  5195.             if (mDialog != null) {
  5196.                 // Save the selection state of each list item
  5197.  
  5198.                 mSelection = mDialog.getListView().getCheckedItemPositions();
  5199.  
  5200.                 mDialog.dismiss();
  5201.                 mDialog = null;
  5202.                 return true;
  5203.             }
  5204.             return false;
  5205.         }
  5206.  
  5207.         public void show(MessageList messageList) {
  5208.             show(messageList, null);
  5209.         }
  5210.  
  5211.         public void show(final MessageList messageList,
  5212.                 SparseBooleanArray selection) {
  5213.             List<String> contents = new ArrayList<String>();
  5214.  
  5215.             if (mImportContents.globalSettings) {
  5216.                 contents.add(messageList
  5217.                         .getString(R.string.settings_import_global_settings));
  5218.             }
  5219.  
  5220.             for (AccountDescription account : mImportContents.accounts) {
  5221.                 contents.add(account.name);
  5222.             }
  5223.  
  5224.             int count = contents.size();
  5225.             boolean[] checkedItems = new boolean[count];
  5226.             if (selection != null) {
  5227.                 for (int i = 0; i < count; i++) {
  5228.                     checkedItems[i] = selection.get(i);
  5229.                 }
  5230.             } else {
  5231.                 for (int i = 0; i < count; i++) {
  5232.                     checkedItems[i] = true;
  5233.                 }
  5234.             }
  5235.  
  5236.             // TODO: listview header:
  5237.             // "Please select the settings you wish to import"
  5238.             // TODO: listview footer: "Select all" / "Select none" buttons?
  5239.             // TODO: listview footer: "Overwrite existing accounts?" checkbox
  5240.  
  5241.             OnMultiChoiceClickListener listener = new OnMultiChoiceClickListener() {
  5242.                 @Override
  5243.                 public void onClick(DialogInterface dialog, int which,
  5244.                         boolean isChecked) {
  5245.                     ((AlertDialog) dialog).getListView().setItemChecked(which,
  5246.                             isChecked);
  5247.                 }
  5248.             };
  5249.  
  5250.             final AlertDialog.Builder builder = new AlertDialog.Builder(
  5251.                     messageList);
  5252.             builder.setMultiChoiceItems(contents.toArray(new String[0]),
  5253.                     checkedItems, listener);
  5254.             builder.setTitle(messageList
  5255.                     .getString(R.string.settings_import_selection));
  5256.             builder.setInverseBackgroundForced(true);
  5257.             builder.setPositiveButton(R.string.okay_action,
  5258.                     new DialogInterface.OnClickListener() {
  5259.  
  5260.                         @Override
  5261.                         public void onClick(DialogInterface dialog, int which) {
  5262.                             ListView listView = ((AlertDialog) dialog)
  5263.                                     .getListView();
  5264.                             SparseBooleanArray pos = listView
  5265.                                     .getCheckedItemPositions();
  5266.  
  5267.                             boolean includeGlobals = mImportContents.globalSettings ? pos
  5268.                                     .get(0) : false;
  5269.                             List<String> accountUuids = new ArrayList<String>();
  5270.                             int start = mImportContents.globalSettings ? 1 : 0;
  5271.                             for (int i = start, end = listView.getCount(); i < end; i++) {
  5272.                                 if (pos.get(i)) {
  5273.                                     accountUuids.add(mImportContents.accounts
  5274.                                             .get(i - start).uuid);
  5275.                                 }
  5276.                             }
  5277.  
  5278.                             /*
  5279.                              * TODO: Think some more about this. Overwriting
  5280.                              * could change the store type. This requires some
  5281.                              * additional code in order to work smoothly while
  5282.                              * the app is running.
  5283.                              */
  5284.                             boolean overwrite = false;
  5285.  
  5286.                             dialog.dismiss();
  5287.                             messageList.setNonConfigurationInstance(null);
  5288.  
  5289.                             ImportAsyncTask importAsyncTask = new ImportAsyncTask(
  5290.                                     messageList, includeGlobals, accountUuids,
  5291.                                     overwrite, mUri);
  5292.                             messageList
  5293.                                     .setNonConfigurationInstance(importAsyncTask);
  5294.                             importAsyncTask.execute();
  5295.                         }
  5296.                     });
  5297.             builder.setNegativeButton(R.string.cancel_action,
  5298.                     new DialogInterface.OnClickListener() {
  5299.                         @Override
  5300.                         public void onClick(DialogInterface dialog, int which) {
  5301.                             dialog.dismiss();
  5302.                             messageList.setNonConfigurationInstance(null);
  5303.                         }
  5304.                     });
  5305.             mDialog = builder.show();
  5306.         }
  5307.     }
  5308.  
  5309.     /**
  5310.      * Set the {@code NonConfigurationInstance} this activity should retain on
  5311.      * configuration changes.
  5312.      *
  5313.      * @param inst
  5314.      *            The {@link NonConfigurationInstance} that should be retained
  5315.      *            when {@link Accounts#onRetainNonConfigurationInstance()} is
  5316.      *            called.
  5317.      */
  5318.     void setNonConfigurationInstance(NonConfigurationInstance inst) {
  5319.         mNonConfigurationInstance = inst;
  5320.     }
  5321.  
  5322.     public class AccountsAdapter1 extends ArrayAdapter<BaseAccount> {
  5323.         public AccountsAdapter1(BaseAccount[] accounts) {
  5324.             super(MessageList.this, 0, accounts);
  5325.         }
  5326.  
  5327.         @Override
  5328.         public View getView(int position, View convertView, ViewGroup parent) {
  5329.             final BaseAccount account = getItem(position);
  5330.             View view;
  5331.             if (convertView != null) {
  5332.                 view = convertView;
  5333.             } else {
  5334.                 view = getLayoutInflater().inflate(R.layout.accounts_item,
  5335.                         parent, false);
  5336.             }
  5337.             AccountViewHolder holder = (AccountViewHolder) view.getTag();
  5338.             if (holder == null) {
  5339.                 holder = new AccountViewHolder();
  5340.                 holder.description = (TextView) view
  5341.                         .findViewById(R.id.description);
  5342.                 holder.email = (TextView) view.findViewById(R.id.email);
  5343.                 holder.newMessageCount = (TextView) view
  5344.                         .findViewById(R.id.new_message_count);
  5345.                 holder.flaggedMessageCount = (TextView) view
  5346.                         .findViewById(R.id.flagged_message_count);
  5347.                 holder.newMessageCountWrapper = view
  5348.                         .findViewById(R.id.new_message_count_wrapper);
  5349.                 holder.flaggedMessageCountWrapper = view
  5350.                         .findViewById(R.id.flagged_message_count_wrapper);
  5351.                 holder.newMessageCountIcon = view
  5352.                         .findViewById(R.id.new_message_count_icon);
  5353.                 holder.flaggedMessageCountIcon = view
  5354.                         .findViewById(R.id.flagged_message_count_icon);
  5355.                 holder.activeIcons = (RelativeLayout) view
  5356.                         .findViewById(R.id.active_icons);
  5357.                 holder.chip = view.findViewById(R.id.chip);
  5358.                 holder.folders = (ImageButton) view.findViewById(R.id.folders);
  5359.                 holder.accountsItemLayout = (LinearLayout) view
  5360.                         .findViewById(R.id.accounts_item_layout);
  5361.  
  5362.                 view.setTag(holder);
  5363.             }
  5364.             AccountStats stats = accountStats.get(account.getUuid());
  5365.  
  5366.             if (stats != null && account instanceof Account && stats.size >= 0) {
  5367.                 holder.email.setText(SizeFormatter.formatSize(MessageList.this,
  5368.                         stats.size));
  5369.                 holder.email.setVisibility(View.VISIBLE);
  5370.             } else {
  5371.                 if (account.getEmail().equals(account.getDescription())) {
  5372.                     holder.email.setVisibility(View.GONE);
  5373.                 } else {
  5374.                     holder.email.setVisibility(View.VISIBLE);
  5375.                     holder.email.setText(account.getEmail());
  5376.                 }
  5377.             }
  5378.  
  5379.             String description = account.getDescription();
  5380.             if (description == null || description.isEmpty()) {
  5381.                 description = account.getEmail();
  5382.             }
  5383.  
  5384.             holder.description.setText(description);
  5385.  
  5386.             Integer unreadMessageCount = null;
  5387.             if (stats != null) {
  5388.                 unreadMessageCount = stats.unreadMessageCount;
  5389.                 holder.newMessageCount.setText(Integer
  5390.                         .toString(unreadMessageCount));
  5391.                 holder.newMessageCountWrapper
  5392.                         .setVisibility(unreadMessageCount > 0 ? View.VISIBLE
  5393.                                 : View.GONE);
  5394.  
  5395.                 holder.flaggedMessageCount.setText(Integer
  5396.                         .toString(stats.flaggedMessageCount));
  5397.                 holder.flaggedMessageCountWrapper
  5398.                         .setVisibility(K9.messageListStars()
  5399.                                 && stats.flaggedMessageCount > 0 ? View.VISIBLE
  5400.                                 : View.GONE);
  5401.  
  5402.                 holder.flaggedMessageCountWrapper
  5403.                         .setOnClickListener(createFlaggedSearchListener(account));
  5404.                 holder.newMessageCountWrapper
  5405.                         .setOnClickListener(createUnreadSearchListener(account));
  5406.  
  5407.                 holder.activeIcons.setOnClickListener(new OnClickListener() {
  5408.                     @Override
  5409.                     public void onClick(View v) {
  5410.                         Toast toast = Toast.makeText(getApplication(),
  5411.                                 getString(R.string.tap_hint),
  5412.                                 Toast.LENGTH_SHORT);
  5413.                         toast.show();
  5414.                     }
  5415.                 });
  5416.  
  5417.             } else {
  5418.                 holder.newMessageCountWrapper.setVisibility(View.GONE);
  5419.                 holder.flaggedMessageCountWrapper.setVisibility(View.GONE);
  5420.             }
  5421.             if (account instanceof Account) {
  5422.                 Account realAccount = (Account) account;
  5423.  
  5424.             } else {
  5425.  
  5426.             }
  5427.  
  5428.             mFontSizes.setViewTextSize(holder.description,
  5429.                     mFontSizes.getAccountName());
  5430.             mFontSizes.setViewTextSize(holder.email,
  5431.                     mFontSizes.getAccountDescription());
  5432.  
  5433.             if (account instanceof SearchAccount) {
  5434.                 holder.folders.setVisibility(View.GONE);
  5435.             } else {
  5436.                 holder.folders.setVisibility(View.VISIBLE);
  5437.                 holder.folders.setOnClickListener(new OnClickListener() {
  5438.                     @Override
  5439.                     public void onClick(View v) {
  5440.  
  5441.                         Log.d("clicked_folder1", "clicked");
  5442.  
  5443.                         FolderList.actionHandleAccount(MessageList.this,
  5444.                                 (Account) account);
  5445.  
  5446.                     }
  5447.                 });
  5448.             }
  5449.  
  5450.             if (account instanceof Account) {
  5451.                 Account realAccount = (Account) account;
  5452.                 holder.chip.setBackgroundColor(realAccount.getChipColor());
  5453.             } else {
  5454.                 holder.chip.setBackgroundColor(0xff999999);
  5455.             }
  5456.  
  5457.             holder.chip.getBackground().setAlpha(255);
  5458.  
  5459.             return view;
  5460.         }
  5461.  
  5462.         private OnClickListener createFlaggedSearchListener(BaseAccount account) {
  5463.             String searchTitle = getString(R.string.search_title,
  5464.                     account.getDescription(),
  5465.                     getString(R.string.flagged_modifier));
  5466.  
  5467.             Log.d("clicked_folder2", "clicked");
  5468.  
  5469.             LocalSearch search;
  5470.             if (account instanceof SearchAccount) {
  5471.                 search = ((SearchAccount) account).getRelatedSearch().clone();
  5472.                 search.setName(searchTitle);
  5473.             } else {
  5474.                 search = new LocalSearch(searchTitle);
  5475.                 search.addAccountUuid(account.getUuid());
  5476.  
  5477.                 Account realAccount = (Account) account;
  5478.                 realAccount.excludeSpecialFolders(search);
  5479.                 realAccount.limitToDisplayableFolders(search);
  5480.             }
  5481.  
  5482.             search.and(Searchfield.FLAGGED, "1", Attribute.EQUALS);
  5483.  
  5484.             return new AccountClickListener(search);
  5485.         }
  5486.  
  5487.         private OnClickListener createUnreadSearchListener(BaseAccount account) {
  5488.             LocalSearch search = Accounts.createUnreadSearch(MessageList.this,
  5489.                     account);
  5490.             return new AccountClickListener(search);
  5491.         }
  5492.  
  5493.         class AccountViewHolder {
  5494.             public TextView description;
  5495.             public TextView email;
  5496.             public TextView newMessageCount;
  5497.             public TextView flaggedMessageCount;
  5498.             public View newMessageCountIcon;
  5499.             public View flaggedMessageCountIcon;
  5500.             public View newMessageCountWrapper;
  5501.             public View flaggedMessageCountWrapper;
  5502.             public View chip;
  5503.             public RelativeLayout activeIcons;
  5504.  
  5505.             public ImageButton folders;
  5506.             public LinearLayout accountsItemLayout;
  5507.         }
  5508.     }
  5509.  
  5510.     /**
  5511.      * Handles exporting of global settings and/or accounts in a background
  5512.      * thread.
  5513.      */
  5514.     private static class ExportAsyncTask extends
  5515.             ExtendedAsyncTask<Void, Void, Boolean> {
  5516.         private boolean mIncludeGlobals;
  5517.         private Set<String> mAccountUuids;
  5518.         private String mFileName;
  5519.  
  5520.         private ExportAsyncTask(Activity accountClickListener,
  5521.                 boolean includeGlobals, Set<String> accountUuids) {
  5522.             super(accountClickListener);
  5523.             mIncludeGlobals = includeGlobals;
  5524.             mAccountUuids = accountUuids;
  5525.         }
  5526.  
  5527.         @Override
  5528.         protected void showProgressDialog() {
  5529.             String title = mContext
  5530.                     .getString(R.string.settings_export_dialog_title);
  5531.             String message = mContext.getString(R.string.settings_exporting);
  5532.             mProgressDialog = ProgressDialog.show(mActivity, title, message,
  5533.                     true);
  5534.         }
  5535.  
  5536.         @Override
  5537.         protected Boolean doInBackground(Void... params) {
  5538.             try {
  5539.                 mFileName = SettingsExporter.exportToFile(mContext,
  5540.                         mIncludeGlobals, mAccountUuids);
  5541.             } catch (SettingsImportExportException e) {
  5542.                 Log.w(K9.LOG_TAG, "Exception during export", e);
  5543.                 return false;
  5544.             }
  5545.             return true;
  5546.         }
  5547.  
  5548.         @Override
  5549.         protected void onPostExecute(Boolean success) {
  5550.             MessageList activity = (MessageList) mActivity;
  5551.  
  5552.             // Let the activity know that the background task is complete
  5553.             activity.setNonConfigurationInstance(null);
  5554.  
  5555.             removeProgressDialog();
  5556.  
  5557.             if (success) {
  5558.                 activity.showSimpleDialog(
  5559.                         R.string.settings_export_success_header,
  5560.                         R.string.settings_export_success, mFileName);
  5561.             } else {
  5562.                 // TODO: better error messages
  5563.                 activity.showSimpleDialog(
  5564.                         R.string.settings_export_failed_header,
  5565.                         R.string.settings_export_failure);
  5566.             }
  5567.         }
  5568.     }
  5569.  
  5570.     /**
  5571.      * Handles importing of global settings and/or accounts in a background
  5572.      * thread.
  5573.      */
  5574.     private static class ImportAsyncTask extends
  5575.             ExtendedAsyncTask<Void, Void, Boolean> {
  5576.         private boolean mIncludeGlobals;
  5577.         private List<String> mAccountUuids;
  5578.         private boolean mOverwrite;
  5579.         private Uri mUri;
  5580.         private ImportResults mImportResults;
  5581.  
  5582.         private ImportAsyncTask(MessageList messageList,
  5583.                 boolean includeGlobals, List<String> accountUuids,
  5584.                 boolean overwrite, Uri uri) {
  5585.             super(messageList);
  5586.             mIncludeGlobals = includeGlobals;
  5587.             mAccountUuids = accountUuids;
  5588.             mOverwrite = overwrite;
  5589.             mUri = uri;
  5590.         }
  5591.  
  5592.         @Override
  5593.         protected void showProgressDialog() {
  5594.             String title = mContext
  5595.                     .getString(R.string.settings_import_dialog_title);
  5596.             String message = mContext.getString(R.string.settings_importing);
  5597.             mProgressDialog = ProgressDialog.show(mActivity, title, message,
  5598.                     true);
  5599.         }
  5600.  
  5601.         @Override
  5602.         protected Boolean doInBackground(Void... params) {
  5603.             try {
  5604.                 InputStream is = mContext.getContentResolver().openInputStream(
  5605.                         mUri);
  5606.                 try {
  5607.                     mImportResults = SettingsImporter.importSettings(mContext,
  5608.                             is, mIncludeGlobals, mAccountUuids, mOverwrite);
  5609.                 } finally {
  5610.                     try {
  5611.                         is.close();
  5612.                     } catch (IOException e) {
  5613.                         /* Ignore */
  5614.                     }
  5615.                 }
  5616.             } catch (SettingsImportExportException e) {
  5617.                 Log.w(K9.LOG_TAG, "Exception during import", e);
  5618.                 return false;
  5619.             } catch (FileNotFoundException e) {
  5620.                 Log.w(K9.LOG_TAG, "Couldn't open import file", e);
  5621.                 return false;
  5622.             } catch (Exception e) {
  5623.                 Log.w(K9.LOG_TAG, "Unknown error", e);
  5624.                 return false;
  5625.             }
  5626.             return true;
  5627.         }
  5628.  
  5629.         @Override
  5630.         protected void onPostExecute(Boolean success) {
  5631.             MessageList activity = (MessageList) mActivity;
  5632.  
  5633.             // Let the activity know that the background task is complete
  5634.             activity.setNonConfigurationInstance(null);
  5635.  
  5636.             removeProgressDialog();
  5637.  
  5638.             String filename = mUri.getLastPathSegment();
  5639.             boolean globalSettings = mImportResults.globalSettings;
  5640.             int imported = mImportResults.importedAccounts.size();
  5641.             if (success && (globalSettings || imported > 0)) {
  5642.                 if (imported == 0) {
  5643.                     activity.showSimpleDialog(
  5644.                             R.string.settings_import_success_header,
  5645.                             R.string.settings_import_global_settings_success,
  5646.                             filename);
  5647.                 } else {
  5648.                     activity.showAccountsImportedDialog(mImportResults,
  5649.                             filename);
  5650.                 }
  5651.  
  5652.                 activity.refresh();
  5653.             } else {
  5654.                 // TODO: better error messages
  5655.                 activity.showSimpleDialog(
  5656.                         R.string.settings_import_failed_header,
  5657.                         R.string.settings_import_failure, filename);
  5658.             }
  5659.         }
  5660.     }
  5661.  
  5662.     static class ListImportContentsAsyncTask extends
  5663.             ExtendedAsyncTask<Void, Void, Boolean> {
  5664.         private Uri mUri;
  5665.         private ImportContents mImportContents;
  5666.  
  5667.         private ListImportContentsAsyncTask(MessageList messageList, Uri uri) {
  5668.             super(messageList);
  5669.  
  5670.             mUri = uri;
  5671.         }
  5672.  
  5673.         @Override
  5674.         protected void showProgressDialog() {
  5675.             String title = mContext
  5676.                     .getString(R.string.settings_import_dialog_title);
  5677.             String message = mContext
  5678.                     .getString(R.string.settings_import_scanning_file);
  5679.             mProgressDialog = ProgressDialog.show(mActivity, title, message,
  5680.                     true);
  5681.         }
  5682.  
  5683.         @Override
  5684.         protected Boolean doInBackground(Void... params) {
  5685.             try {
  5686.                 ContentResolver resolver = mContext.getContentResolver();
  5687.                 InputStream is = resolver.openInputStream(mUri);
  5688.                 try {
  5689.                     mImportContents = SettingsImporter
  5690.                             .getImportStreamContents(is);
  5691.                 } finally {
  5692.                     try {
  5693.                         is.close();
  5694.                     } catch (IOException e) {
  5695.                         /* Ignore */
  5696.                     }
  5697.                 }
  5698.             } catch (SettingsImportExportException e) {
  5699.                 Log.w(K9.LOG_TAG, "Exception during export", e);
  5700.                 return false;
  5701.             } catch (FileNotFoundException e) {
  5702.                 Log.w(K9.LOG_TAG, "Couldn't read content from URI " + mUri);
  5703.                 return false;
  5704.             }
  5705.             return true;
  5706.         }
  5707.  
  5708.         @Override
  5709.         protected void onPostExecute(Boolean success) {
  5710.             MessageList activity = (MessageList) mActivity;
  5711.  
  5712.             // Let the activity know that the background task is complete
  5713.             activity.setNonConfigurationInstance(null);
  5714.  
  5715.             removeProgressDialog();
  5716.  
  5717.             if (success) {
  5718.                 activity.showImportSelectionDialog(mImportContents, mUri);
  5719.             } else {
  5720.                 String filename = mUri.getLastPathSegment();
  5721.                 // TODO: better error messages
  5722.                 activity.showSimpleDialog(
  5723.                         R.string.settings_import_failed_header,
  5724.                         R.string.settings_import_failure, filename);
  5725.             }
  5726.         }
  5727.     }
  5728.  
  5729.     private static class MoveAccountAsyncTask extends
  5730.             ExtendedAsyncTask<Void, Void, Void> {
  5731.         private Account mAccount;
  5732.         private boolean mUp;
  5733.  
  5734.         protected MoveAccountAsyncTask(Activity activity, Account account,
  5735.                 boolean up) {
  5736.             super(activity);
  5737.             mAccount = account;
  5738.             mUp = up;
  5739.         }
  5740.  
  5741.         @Override
  5742.         protected void showProgressDialog() {
  5743.             String message = mActivity
  5744.                     .getString(R.string.manage_accounts_moving_message);
  5745.             mProgressDialog = ProgressDialog.show(mActivity, null, message,
  5746.                     true);
  5747.         }
  5748.  
  5749.         @Override
  5750.         protected Void doInBackground(Void... args) {
  5751.             mAccount.move(Preferences.getPreferences(mContext), mUp);
  5752.             return null;
  5753.         }
  5754.  
  5755.         @Override
  5756.         protected void onPostExecute(Void arg) {
  5757.             MessageList activity = (MessageList) mActivity;
  5758.  
  5759.             // Let the activity know that the background task is complete
  5760.             activity.setNonConfigurationInstance(null);
  5761.  
  5762.             activity.refresh();
  5763.             removeProgressDialog();
  5764.         }
  5765.     }
  5766.  
  5767.     private void createSpecialAccounts() {
  5768.         mUnifiedInboxAccount = SearchAccount.createUnifiedInboxAccount(this);
  5769.         mAllMessagesAccount = SearchAccount.createAllMessagesAccount(this);
  5770.     }
  5771.  
  5772.     void refresh() {
  5773.         accounts = Preferences.getPreferences(this).getAccounts();
  5774.  
  5775.         // see if we should show the welcome message
  5776.         // if (accounts.length < 1) {
  5777.         // WelcomeMessage.showWelcomeMessage(this);
  5778.         // finish();
  5779.         // }
  5780.  
  5781.         List<BaseAccount> newAccounts;
  5782.         if (!K9.isHideSpecialAccounts() && accounts.length > 0) {
  5783.             if (mUnifiedInboxAccount == null || mAllMessagesAccount == null) {
  5784.                 createSpecialAccounts();
  5785.             }
  5786.  
  5787.             newAccounts = new ArrayList<BaseAccount>(accounts.length
  5788.                     + SPECIAL_ACCOUNTS_COUNT);
  5789.             newAccounts.add(mUnifiedInboxAccount);
  5790.             newAccounts.add(mAllMessagesAccount);
  5791.         } else {
  5792.             newAccounts = new ArrayList<BaseAccount>(accounts.length);
  5793.         }
  5794.  
  5795.         newAccounts.addAll(Arrays.asList(accounts));
  5796.  
  5797.         mAdapter_Accounts = new AccountsAdapter1(
  5798.                 newAccounts.toArray(EMPTY_BASE_ACCOUNT_ARRAY));
  5799.  
  5800.         getListView().setAdapter(mAdapter);
  5801.         if (!newAccounts.isEmpty()) {
  5802.  
  5803.         }
  5804.         pendingWork.clear();
  5805.         mHandler.refreshTitle();
  5806.  
  5807.         MessagingController controller = MessagingController
  5808.                 .getInstance(getApplication());
  5809.  
  5810.         for (BaseAccount account : newAccounts) {
  5811.             pendingWork.put(account, "true");
  5812.  
  5813.             if (account instanceof Account) {
  5814.                 Account realAccount = (Account) account;
  5815.                 controller.getAccountStats(this, realAccount,
  5816.                         mListener_Accounts);
  5817.             } else if (K9.countSearchMessages()
  5818.                     && account instanceof SearchAccount) {
  5819.                 final SearchAccount searchAccount = (SearchAccount) account;
  5820.                 controller.getSearchAccountStats(searchAccount,
  5821.                         mListener_Accounts);
  5822.             }
  5823.         }
  5824.     }
  5825. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement