diff --git a/k9mail/src/main/AndroidManifest.xml b/k9mail/src/main/AndroidManifest.xml index e5a064a40..d3c84a290 100644 --- a/k9mail/src/main/AndroidManifest.xml +++ b/k9mail/src/main/AndroidManifest.xml @@ -144,6 +144,13 @@ android:configChanges="locale" android:label="@string/account_setup_names_title"/> + + queryArgs = new ArrayList<>(); + ConditionsTreeNode conditions = search.getConditions(); + SqlQueryBuilder.buildWhereClause(this, conditions, query, queryArgs); + + String selection = query.toString(); + String[] selectionArgs = queryArgs.toArray(new String[queryArgs.size()]); + + return cr.query(uri, projection, selection, selectionArgs, null); + } + public synchronized void setChipColor(int color) { chipColor = color; diff --git a/k9mail/src/main/java/com/fsck/k9/activity/ChooseAccount.java b/k9mail/src/main/java/com/fsck/k9/activity/ChooseAccount.java new file mode 100644 index 000000000..b45ed10a3 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/activity/ChooseAccount.java @@ -0,0 +1,23 @@ +package com.fsck.k9.activity; + +import android.content.Intent; + +import com.fsck.k9.BaseAccount; + +public class ChooseAccount extends AccountList { + + public static final String EXTRA_ACCOUNT_UUID = "com.fsck.k9.ChooseAccount_account_uuid"; + + @Override + protected boolean displaySpecialAccounts() { + return true; + } + + @Override + protected void onAccountSelected(BaseAccount account) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_ACCOUNT_UUID, account.getUuid()); + setResult(RESULT_OK, intent); + finish(); + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/activity/UnreadWidgetConfiguration.java b/k9mail/src/main/java/com/fsck/k9/activity/UnreadWidgetConfiguration.java index 6b049b688..5d1726ca8 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/UnreadWidgetConfiguration.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/UnreadWidgetConfiguration.java @@ -6,32 +6,55 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; -import com.fsck.k9.BaseAccount; +import com.fsck.k9.Account; +import com.fsck.k9.Preferences; import com.fsck.k9.R; +import com.fsck.k9.helper.UnreadWidgetProperties; import com.fsck.k9.provider.UnreadWidgetProvider; +import com.fsck.k9.search.SearchAccount; + +import timber.log.Timber; /** * Activity to select an account for the unread widget. */ -public class UnreadWidgetConfiguration extends AccountList { +public class UnreadWidgetConfiguration extends K9PreferenceActivity { /** * Name of the preference file to store the widget configuration. */ private static final String PREFS_NAME = "unread_widget_configuration.xml"; /** - * Prefix for the preference keys. + * Prefixes for the preference keys */ private static final String PREF_PREFIX_KEY = "unread_widget."; + private static final String PREF_FOLDER_NAME_SUFFIX_KEY = ".folder_name"; + private static final String PREFERENCE_UNREAD_ACCOUNT = "unread_account"; + private static final String PREFERENCE_UNREAD_FOLDER_ENABLED = "unread_folder_enabled"; + private static final String PREFERENCE_UNREAD_FOLDER = "unread_folder"; /** * The ID of the widget we are configuring. */ - private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; + private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; + private static final int REQUEST_CHOOSE_ACCOUNT = 1; + private static final int REQUEST_CHOOSE_FOLDER = 2; + + private Preference unreadAccount; + private CheckBoxPreference unreadFolderEnabled; + private Preference unreadFolder; + + private String selectedAccountUuid; + private String selectedFolderName; @Override public void onCreate(Bundle icicle) { @@ -41,58 +64,173 @@ public class UnreadWidgetConfiguration extends AccountList { Intent intent = getIntent(); Bundle extras = intent.getExtras(); if (extras != null) { - mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, + appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } // If they gave us an intent without the widget ID, just bail. - if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + Timber.e("Received an invalid widget ID"); finish(); return; } + addPreferencesFromResource(R.xml.unread_widget_configuration); + unreadAccount = findPreference(PREFERENCE_UNREAD_ACCOUNT); + unreadAccount.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(UnreadWidgetConfiguration.this, ChooseAccount.class); + startActivityForResult(intent, REQUEST_CHOOSE_ACCOUNT); + return false; + } + }); + + unreadFolderEnabled = (CheckBoxPreference) findPreference(PREFERENCE_UNREAD_FOLDER_ENABLED); + unreadFolderEnabled.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + unreadFolder.setSummary(getString(R.string.unread_widget_folder_summary)); + selectedFolderName = null; + return true; + } + }); + + unreadFolder = findPreference(PREFERENCE_UNREAD_FOLDER); + unreadFolder.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(UnreadWidgetConfiguration.this, ChooseFolder.class); + intent.putExtra(ChooseFolder.EXTRA_ACCOUNT, selectedAccountUuid); + intent.putExtra(ChooseFolder.EXTRA_SHOW_DISPLAYABLE_ONLY, "yes"); + startActivityForResult(intent, REQUEST_CHOOSE_FOLDER); + return false; + } + }); setTitle(R.string.unread_widget_select_account); } @Override - protected boolean displaySpecialAccounts() { + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) { + switch (requestCode) { + case REQUEST_CHOOSE_ACCOUNT: + handleChooseAccount(data.getStringExtra(ChooseAccount.EXTRA_ACCOUNT_UUID)); + break; + case REQUEST_CHOOSE_FOLDER: + handleChooseFolder(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER)); + break; + } + } + super.onActivityResult(requestCode, resultCode, data); + } + + private void handleChooseAccount(String accountUuid) { + selectedAccountUuid = accountUuid; + unreadFolder.setSummary(getString(R.string.unread_widget_folder_summary)); + if (SearchAccount.UNIFIED_INBOX.equals(selectedAccountUuid) || + SearchAccount.ALL_MESSAGES.equals(selectedAccountUuid)) { + handleSearchAccount(); + } else { + handleRegularAccount(); + } + } + + private void handleSearchAccount() { + if (SearchAccount.UNIFIED_INBOX.equals(selectedAccountUuid)) { + unreadAccount.setSummary(R.string.unread_widget_unified_inbox_account_summary); + } else if (SearchAccount.ALL_MESSAGES.equals(selectedAccountUuid)) { + unreadAccount.setSummary(R.string.unread_widget_all_messages_account_summary); + } + unreadFolderEnabled.setEnabled(false); + unreadFolderEnabled.setChecked(false); + unreadFolder.setEnabled(false); + selectedFolderName = null; + } + + private void handleRegularAccount() { + Account selectedAccount = Preferences.getPreferences(this).getAccount(selectedAccountUuid); + String summary = selectedAccount.getDescription(); + if (summary == null || summary.isEmpty()) { + summary = selectedAccount.getEmail(); + } + unreadAccount.setSummary(summary); + unreadFolderEnabled.setEnabled(true); + unreadFolder.setEnabled(true); + } + + private void handleChooseFolder(String folderName) { + selectedFolderName = folderName; + unreadFolder.setSummary(selectedFolderName); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.unread_widget_option, menu); return true; } @Override - protected void onAccountSelected(BaseAccount account) { - // Save widget configuration - String accountUuid = account.getUuid(); - saveAccountUuid(this, mAppWidgetId, accountUuid); + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.done: + if (validateWidget()) { + updateWidgetAndExit(); + } + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private boolean validateWidget() { + if (selectedAccountUuid == null) { + Toast.makeText(this, R.string.unread_widget_account_not_selected, Toast.LENGTH_LONG).show(); + return false; + } else if (unreadFolderEnabled.isChecked() && selectedFolderName == null) { + Toast.makeText(this, R.string.unread_widget_folder_not_selected, Toast.LENGTH_LONG).show(); + return false; + } + return true; + } + + private void updateWidgetAndExit() { + UnreadWidgetProperties properties = new UnreadWidgetProperties(appWidgetId, selectedAccountUuid,selectedFolderName); + saveWidgetProperties(this, properties); // Update widget Context context = getApplicationContext(); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); - UnreadWidgetProvider.updateWidget(context, appWidgetManager, mAppWidgetId, accountUuid); + UnreadWidgetProvider.updateWidget(context, appWidgetManager, properties); // Let the caller know that the configuration was successful Intent resultValue = new Intent(); - resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); setResult(RESULT_OK, resultValue); finish(); } - private static void saveAccountUuid(Context context, int appWidgetId, String accountUuid) { + private static void saveWidgetProperties(Context context, UnreadWidgetProperties properties) { + int appWidgetId = properties.getAppWidgetId(); SharedPreferences.Editor editor = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit(); - editor.putString(PREF_PREFIX_KEY + appWidgetId, accountUuid); - editor.commit(); + editor.putString(PREF_PREFIX_KEY + appWidgetId, properties.getAccountUuid()); + editor.putString(PREF_PREFIX_KEY + appWidgetId + PREF_FOLDER_NAME_SUFFIX_KEY, properties.getFolderName()); + editor.apply(); } - public static String getAccountUuid(Context context, int appWidgetId) { + public static UnreadWidgetProperties getWidgetProperties(Context context, int appWidgetId) { SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); String accountUuid = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null); - return accountUuid; + String folderName = prefs.getString(PREF_PREFIX_KEY + appWidgetId + PREF_FOLDER_NAME_SUFFIX_KEY, null); + return new UnreadWidgetProperties(appWidgetId, accountUuid, folderName); } public static void deleteWidgetConfiguration(Context context, int appWidgetId) { Editor editor = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit(); editor.remove(PREF_PREFIX_KEY + appWidgetId); - editor.commit(); + editor.remove(PREF_PREFIX_KEY + appWidgetId + PREF_FOLDER_NAME_SUFFIX_KEY); + editor.apply(); } } diff --git a/k9mail/src/main/java/com/fsck/k9/helper/UnreadWidgetProperties.java b/k9mail/src/main/java/com/fsck/k9/helper/UnreadWidgetProperties.java new file mode 100644 index 000000000..9ea867406 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/helper/UnreadWidgetProperties.java @@ -0,0 +1,138 @@ +package com.fsck.k9.helper; + +import android.content.Context; +import android.content.Intent; + +import com.fsck.k9.Account; +import com.fsck.k9.AccountStats; +import com.fsck.k9.BaseAccount; +import com.fsck.k9.K9; +import com.fsck.k9.Preferences; +import com.fsck.k9.R; +import com.fsck.k9.activity.FolderList; +import com.fsck.k9.activity.MessageList; +import com.fsck.k9.controller.MessagingController; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.search.LocalSearch; +import com.fsck.k9.search.SearchAccount; + +public class UnreadWidgetProperties { + + private int appWidgetId; + private String accountUuid; + private String folderName; + private Type type; + + public UnreadWidgetProperties(int appWidgetId, String accountUuid, String folderName) { + this.appWidgetId = appWidgetId; + this.accountUuid = accountUuid; + this.folderName = folderName; + calculateType(); + } + + public String getTitle(Context context) { + String accountName = getAccount(context).getDescription(); + switch (type) { + case SEARCH_ACCOUNT: + case ACCOUNT: + return accountName; + case FOLDER: + return context.getString(R.string.unread_widget_title, accountName, folderName); + default: + return null; + } + } + + public int getUnreadCount(Context context) throws MessagingException { + BaseAccount baseAccount = getAccount(context); + AccountStats stats; + switch (type) { + case SEARCH_ACCOUNT: + MessagingController controller = MessagingController.getInstance(context); + stats = controller.getSearchAccountStatsSynchronous((SearchAccount) baseAccount, null); + return stats.unreadMessageCount; + case ACCOUNT: + Account account = (Account) baseAccount; + stats = account.getStats(context); + return stats.unreadMessageCount; + case FOLDER: + return ((Account) baseAccount).getFolderUnreadCount(context, folderName); + default: + return -1; + } + } + + public Intent getClickIntent(Context context) { + switch (type) { + case SEARCH_ACCOUNT: + SearchAccount searchAccount = (SearchAccount) getAccount(context); + return MessageList.intentDisplaySearch(context, + searchAccount.getRelatedSearch(), false, true, true); + case ACCOUNT: + return getClickIntentForAccount(context); + case FOLDER: + return getClickIntentForFolder(context); + default: + return null; + } + } + + public int getAppWidgetId() { + return appWidgetId; + } + + public String getAccountUuid() { + return accountUuid; + } + + public String getFolderName() { + return folderName; + } + + private void calculateType() { + if (SearchAccount.UNIFIED_INBOX.equals(accountUuid) || + SearchAccount.ALL_MESSAGES.equals(accountUuid)) { + type = Type.SEARCH_ACCOUNT; + } else if(folderName != null) { + type = Type.FOLDER; + } else { + type = Type.ACCOUNT; + } + } + + private BaseAccount getAccount(Context context) { + if (SearchAccount.UNIFIED_INBOX.equals(accountUuid)) { + return SearchAccount.createUnifiedInboxAccount(context); + } else if (SearchAccount.ALL_MESSAGES.equals(accountUuid)) { + return SearchAccount.createAllMessagesAccount(context); + } + return Preferences.getPreferences(context).getAccount(accountUuid); + } + + private Intent getClickIntentForAccount(Context context) { + Account account = Preferences.getPreferences(context).getAccount(accountUuid); + if (K9.FOLDER_NONE.equals(account.getAutoExpandFolderName())) { + return FolderList.actionHandleAccountIntent(context, account, false); + } + LocalSearch search = new LocalSearch(account.getAutoExpandFolderName()); + search.addAllowedFolder(account.getAutoExpandFolderName()); + search.addAccountUuid(account.getUuid()); + return MessageList.intentDisplaySearch(context, search, false, true, true); + } + + private Intent getClickIntentForFolder(Context context) { + Account account = Preferences.getPreferences(context).getAccount(accountUuid); + LocalSearch search = new LocalSearch(folderName); + search.addAllowedFolder(folderName); + search.addAccountUuid(account.getUuid()); + Intent clickIntent = MessageList.intentDisplaySearch(context, search, false, true, true); + clickIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + return clickIntent; + } + + public enum Type { + SEARCH_ACCOUNT, + ACCOUNT, + FOLDER + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/provider/UnreadWidgetProvider.java b/k9mail/src/main/java/com/fsck/k9/provider/UnreadWidgetProvider.java index 3f4d648ed..c4f85c185 100644 --- a/k9mail/src/main/java/com/fsck/k9/provider/UnreadWidgetProvider.java +++ b/k9mail/src/main/java/com/fsck/k9/provider/UnreadWidgetProvider.java @@ -1,17 +1,8 @@ package com.fsck.k9.provider; -import com.fsck.k9.Account; -import com.fsck.k9.AccountStats; -import com.fsck.k9.BaseAccount; -import com.fsck.k9.K9; -import com.fsck.k9.Preferences; import com.fsck.k9.R; import com.fsck.k9.activity.UnreadWidgetConfiguration; -import com.fsck.k9.activity.FolderList; -import com.fsck.k9.activity.MessageList; -import com.fsck.k9.controller.MessagingController; -import com.fsck.k9.search.LocalSearch; -import com.fsck.k9.search.SearchAccount; +import com.fsck.k9.helper.UnreadWidgetProperties; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; @@ -47,73 +38,35 @@ public class UnreadWidgetProvider extends AppWidgetProvider { } public static void updateWidget(Context context, AppWidgetManager appWidgetManager, - int appWidgetId, String accountUuid) { + UnreadWidgetProperties properties) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.unread_widget_layout); - int unreadCount = 0; - String accountName = context.getString(R.string.app_name); + int appWidgetId = properties.getAppWidgetId(); Intent clickIntent = null; + int unreadCount = 0; + try { - BaseAccount account = null; - AccountStats stats = null; + clickIntent = properties.getClickIntent(context); + unreadCount = properties.getUnreadCount(context); - SearchAccount searchAccount = null; - if (SearchAccount.UNIFIED_INBOX.equals(accountUuid)) { - searchAccount = SearchAccount.createUnifiedInboxAccount(context); - } else if (SearchAccount.ALL_MESSAGES.equals(accountUuid)) { - searchAccount = SearchAccount.createAllMessagesAccount(context); - } - - if (searchAccount != null) { - account = searchAccount; - MessagingController controller = MessagingController.getInstance(context); - stats = controller.getSearchAccountStatsSynchronous(searchAccount, null); - clickIntent = MessageList.intentDisplaySearch(context, - searchAccount.getRelatedSearch(), false, true, true); + if (unreadCount <= 0) { + // Hide TextView for unread count if there are no unread messages. + remoteViews.setViewVisibility(R.id.unread_count, View.GONE); } else { - Account realAccount = Preferences.getPreferences(context).getAccount(accountUuid); - if (realAccount != null) { - account = realAccount; - stats = realAccount.getStats(context); + remoteViews.setViewVisibility(R.id.unread_count, View.VISIBLE); - if (K9.FOLDER_NONE.equals(realAccount.getAutoExpandFolderName())) { - clickIntent = FolderList.actionHandleAccountIntent(context, realAccount, false); - } else { - LocalSearch search = new LocalSearch(realAccount.getAutoExpandFolderName()); - search.addAllowedFolder(realAccount.getAutoExpandFolderName()); - search.addAccountUuid(account.getUuid()); - clickIntent = MessageList.intentDisplaySearch(context, search, false, true, - true); - } - clickIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - } + String displayCount = (unreadCount <= MAX_COUNT) ? + String.valueOf(unreadCount) : String.valueOf(MAX_COUNT) + "+"; + remoteViews.setTextViewText(R.id.unread_count, displayCount); } - if (account != null) { - accountName = account.getDescription(); - } - - if (stats != null) { - unreadCount = stats.unreadMessageCount; - } + remoteViews.setTextViewText(R.id.title, properties.getTitle(context)); } catch (Exception e) { Timber.e(e, "Error getting widget configuration"); } - if (unreadCount <= 0) { - // Hide TextView for unread count if there are no unread messages. - remoteViews.setViewVisibility(R.id.unread_count, View.GONE); - } else { - remoteViews.setViewVisibility(R.id.unread_count, View.VISIBLE); - - String displayCount = (unreadCount <= MAX_COUNT) ? - String.valueOf(unreadCount) : String.valueOf(MAX_COUNT) + "+"; - remoteViews.setTextViewText(R.id.unread_count, displayCount); - } - - remoteViews.setTextViewText(R.id.account_name, accountName); if (clickIntent == null) { // If the widget configuration couldn't be loaded we open the configuration @@ -123,7 +76,6 @@ public class UnreadWidgetProvider extends AppWidgetProvider { } clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, clickIntent, 0); @@ -139,9 +91,8 @@ public class UnreadWidgetProvider extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { for (int widgetId : appWidgetIds) { - String accountUuid = UnreadWidgetConfiguration.getAccountUuid(context, widgetId); - - updateWidget(context, appWidgetManager, widgetId, accountUuid); + UnreadWidgetProperties properties = UnreadWidgetConfiguration.getWidgetProperties(context, widgetId); + updateWidget(context, appWidgetManager, properties); } } diff --git a/k9mail/src/main/res/layout/unread_widget_layout.xml b/k9mail/src/main/res/layout/unread_widget_layout.xml index 1ac11e969..18017e55f 100644 --- a/k9mail/src/main/res/layout/unread_widget_layout.xml +++ b/k9mail/src/main/res/layout/unread_widget_layout.xml @@ -39,7 +39,7 @@ + + + \ No newline at end of file diff --git a/k9mail/src/main/res/values/strings.xml b/k9mail/src/main/res/values/strings.xml index 97ca049b5..bba7d36c2 100644 --- a/k9mail/src/main/res/values/strings.xml +++ b/k9mail/src/main/res/values/strings.xml @@ -98,6 +98,7 @@ Please submit bug reports, contribute new features and ask questions at Reply all Forward + Choose Account Choose Folder Poll %s:%s%s @@ -1023,6 +1024,18 @@ Please submit bug reports, contribute new features and ask questions at Moving account… Show unread count for… + Account + The account for which the unread count should be displayed + Unified Inbox + All messages + Folder count + Display the unread count of only a single folder + Folder + The folder for which the unread count should be displayed + Done + %1$s - %2$s + No account selected + No folder selected Missing File Manager Application Close diff --git a/k9mail/src/main/res/xml/unread_widget_configuration.xml b/k9mail/src/main/res/xml/unread_widget_configuration.xml new file mode 100644 index 000000000..ad11ed608 --- /dev/null +++ b/k9mail/src/main/res/xml/unread_widget_configuration.xml @@ -0,0 +1,24 @@ + + + + + + + + +