Loading k9mail/src/main/AndroidManifest.xml +17 −0 Original line number Diff line number Diff line Loading @@ -356,6 +356,23 @@ android:resource="@xml/unread_widget_info"/> </receiver> <receiver android:name=".widget.list.MessageListWidgetProvider" android:icon="@drawable/message_list_widget_preview" android:label="@string/mail_list_widget_text"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/message_list_widget_info" /> </receiver> <service android:name=".widget.list.MessageListWidgetService" android:enabled="true" android:permission="android.permission.BIND_REMOTEVIEWS" /> <service android:name=".service.MailService" android:enabled="true"/> Loading k9mail/src/main/java/com/fsck/k9/K9.java +17 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.fsck.k9.service.BootReceiver; import com.fsck.k9.service.MailService; import com.fsck.k9.service.ShutdownReceiver; import com.fsck.k9.service.StorageGoneReceiver; import com.fsck.k9.widget.list.MessageListWidgetProvider; public class K9 extends Application { /** Loading Loading @@ -584,22 +585,37 @@ public class K9 extends Application { } } private void updateMailListWidget() { try { MessageListWidgetProvider.triggerMessageListWidgetUpdate(K9.this); } catch (RuntimeException e) { if (BuildConfig.DEBUG) { throw e; } else if (K9.DEBUG) { Log.e(LOG_TAG, "Error while updating message list widget", e); } } } @Override public void synchronizeMailboxRemovedMessage(Account account, String folder, Message message) { broadcastIntent(K9.Intents.EmailReceived.ACTION_EMAIL_DELETED, account, folder, message); updateUnreadWidget(); updateMailListWidget(); } @Override public void messageDeleted(Account account, String folder, Message message) { broadcastIntent(K9.Intents.EmailReceived.ACTION_EMAIL_DELETED, account, folder, message); updateUnreadWidget(); updateMailListWidget(); } @Override public void synchronizeMailboxNewMessage(Account account, String folder, Message message) { broadcastIntent(K9.Intents.EmailReceived.ACTION_EMAIL_RECEIVED, account, folder, message); updateUnreadWidget(); updateMailListWidget(); } @Override Loading @@ -607,6 +623,7 @@ public class K9 extends Application { int unreadMessageCount) { updateUnreadWidget(); updateMailListWidget(); // let observers know a change occurred Intent intent = new Intent(K9.Intents.EmailReceived.ACTION_REFRESH_OBSERVER, null); Loading k9mail/src/main/java/com/fsck/k9/widget/list/MessageListRemoteViewFactory.java 0 → 100644 +209 −0 Original line number Diff line number Diff line package com.fsck.k9.widget.list; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Typeface; import android.net.Uri; import android.os.Binder; import android.support.v4.content.ContextCompat; import android.text.SpannableString; import android.text.style.StyleSpan; import android.view.View; import android.widget.RemoteViews; import android.widget.RemoteViewsService; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.provider.MessageProvider; public class MessageListRemoteViewFactory implements RemoteViewsService.RemoteViewsFactory { private static String[] MAIL_LIST_PROJECTIONS = { MessageProvider.MessageColumns.SENDER, MessageProvider.MessageColumns.SEND_DATE, MessageProvider.MessageColumns.SUBJECT, MessageProvider.MessageColumns.PREVIEW, MessageProvider.MessageColumns.UNREAD, MessageProvider.MessageColumns.HAS_ATTACHMENTS, MessageProvider.MessageColumns.URI }; private final Context context; private final Calendar calendar; private final ArrayList<MailItem> mailItems = new ArrayList<>(25); private boolean senderAboveSubject; private int readTextColor; private int unreadTextColor; public MessageListRemoteViewFactory(Context context) { this.context = context; calendar = Calendar.getInstance(); } @Override public void onCreate() { senderAboveSubject = K9.messageListSenderAboveSubject(); readTextColor = ContextCompat.getColor(context, R.color.message_list_widget_text_read); unreadTextColor = ContextCompat.getColor(context, R.color.message_list_widget_text_unread); } @Override public void onDataSetChanged() { long identityToken = Binder.clearCallingIdentity(); try { loadMessageList(); } finally { Binder.restoreCallingIdentity(identityToken); } } private void loadMessageList() { mailItems.clear(); Uri unifiedInboxUri = MessageProvider.CONTENT_URI.buildUpon().appendPath("inbox_messages").build(); Cursor cursor = context.getContentResolver().query(unifiedInboxUri, MAIL_LIST_PROJECTIONS, null, null, null); if (cursor == null) { return; } try { while (cursor.moveToNext()) { String sender = cursor.getString(0); long date = cursor.isNull(1) ? 0L : cursor.getLong(1); String subject = cursor.getString(2); String preview = cursor.getString(3); boolean unread = toBoolean(cursor.getString(4)); boolean hasAttachment = toBoolean(cursor.getString(5)); Uri viewUri = Uri.parse(cursor.getString(6)); mailItems.add(new MailItem(sender, date, subject, preview, unread, hasAttachment, viewUri)); } } finally { cursor.close(); } } @Override public void onDestroy() { // Implement interface } @Override public int getCount() { return mailItems.size(); } @Override public RemoteViews getViewAt(int position) { RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_list_item); MailItem item = mailItems.get(position); CharSequence sender = item.unread ? bold(item.sender) : item.sender; CharSequence subject = item.unread ? bold(item.subject) : item.subject; if (senderAboveSubject) { remoteView.setTextViewText(R.id.sender, sender); remoteView.setTextViewText(R.id.mail_subject, subject); } else { remoteView.setTextViewText(R.id.sender, subject); remoteView.setTextViewText(R.id.mail_subject, sender); } remoteView.setTextViewText(R.id.mail_date, item.getDateFormatted("%d %s")); remoteView.setTextViewText(R.id.mail_preview, item.preview); int textColor = item.getTextColor(); remoteView.setTextColor(R.id.sender, textColor); remoteView.setTextColor(R.id.mail_subject, textColor); remoteView.setTextColor(R.id.mail_date, textColor); remoteView.setTextColor(R.id.mail_preview, textColor); if (item.hasAttachment) { remoteView.setInt(R.id.attachment, "setVisibility", View.VISIBLE); } else { remoteView.setInt(R.id.attachment, "setVisibility", View.GONE); } Intent intent = new Intent(); intent.setData(item.uri); remoteView.setOnClickFillInIntent(R.id.mail_list_item, intent); return remoteView; } @Override public RemoteViews getLoadingView() { RemoteViews loadingView = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_loading); loadingView.setTextViewText(R.id.loadingText, context.getString(R.string.mail_list_widget_loading)); loadingView.setViewVisibility(R.id.loadingText, View.VISIBLE); return loadingView; } @Override public int getViewTypeCount() { return 2; } @Override public long getItemId(int position) { return position; } @Override public boolean hasStableIds() { return true; } private CharSequence bold(String text) { SpannableString spannableString = new SpannableString(text); spannableString.setSpan(new StyleSpan(Typeface.BOLD), 0, text.length(), 0); return spannableString; } private boolean toBoolean(String value) { return Boolean.valueOf(value); } private class MailItem { final long date; final String sender; final String preview; final String subject; final boolean unread; final boolean hasAttachment; final Uri uri; MailItem(String sender, long date, String subject, String preview, boolean unread, boolean hasAttachment, Uri viewUri) { this.sender = sender; this.date = date; this.preview = preview; this.subject = subject; this.unread = unread; this.uri = viewUri; this.hasAttachment = hasAttachment; } int getTextColor() { return unread ? unreadTextColor : readTextColor; } String getDateFormatted(String format) { calendar.setTimeInMillis(date); return String.format(format, calendar.get(Calendar.DAY_OF_MONTH), calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())); } } } k9mail/src/main/java/com/fsck/k9/widget/list/MessageListWidgetProvider.java 0 → 100644 +85 −0 Original line number Diff line number Diff line package com.fsck.k9.widget.list; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.widget.RemoteViews; import com.fsck.k9.R; import com.fsck.k9.activity.MessageCompose; import com.fsck.k9.activity.MessageList; public class MessageListWidgetProvider extends AppWidgetProvider { private static String ACTION_UPDATE_MESSAGE_LIST = "UPDATE_MESSAGE_LIST"; public static void triggerMessageListWidgetUpdate(Context context) { Context appContext = context.getApplicationContext(); AppWidgetManager widgetManager = AppWidgetManager.getInstance(appContext); ComponentName widget = new ComponentName(appContext, MessageListWidgetProvider.class); int[] widgetIds = widgetManager.getAppWidgetIds(widget); Intent intent = new Intent(context, MessageListWidgetProvider.class); intent.setAction(ACTION_UPDATE_MESSAGE_LIST); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds); context.sendBroadcast(intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } } private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_layout); views.setTextViewText(R.id.folder, context.getString(R.string.integrated_inbox_title)); Intent intent = new Intent(context, MessageListWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); views.setRemoteAdapter(R.id.listView, intent); PendingIntent viewAction = viewActionTemplatePendingIntent(context); views.setPendingIntentTemplate(R.id.listView, viewAction); PendingIntent composeAction = composeActionPendingIntent(context); views.setOnClickPendingIntent(R.id.new_message, composeAction); appWidgetManager.updateAppWidget(appWidgetId, views); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); String action = intent.getAction(); if (action.equals(ACTION_UPDATE_MESSAGE_LIST)) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView); } } private PendingIntent viewActionTemplatePendingIntent(Context context) { Intent intent = new Intent(context, MessageList.class); intent.setAction(Intent.ACTION_VIEW); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } private PendingIntent composeActionPendingIntent(Context context) { Intent intent = new Intent(context, MessageCompose.class); intent.setAction(MessageCompose.ACTION_COMPOSE); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } } k9mail/src/main/java/com/fsck/k9/widget/list/MessageListWidgetService.java 0 → 100644 +13 −0 Original line number Diff line number Diff line package com.fsck.k9.widget.list; import android.content.Intent; import android.widget.RemoteViewsService; public class MessageListWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new MessageListRemoteViewFactory(getApplicationContext()); } } Loading
k9mail/src/main/AndroidManifest.xml +17 −0 Original line number Diff line number Diff line Loading @@ -356,6 +356,23 @@ android:resource="@xml/unread_widget_info"/> </receiver> <receiver android:name=".widget.list.MessageListWidgetProvider" android:icon="@drawable/message_list_widget_preview" android:label="@string/mail_list_widget_text"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/message_list_widget_info" /> </receiver> <service android:name=".widget.list.MessageListWidgetService" android:enabled="true" android:permission="android.permission.BIND_REMOTEVIEWS" /> <service android:name=".service.MailService" android:enabled="true"/> Loading
k9mail/src/main/java/com/fsck/k9/K9.java +17 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.fsck.k9.service.BootReceiver; import com.fsck.k9.service.MailService; import com.fsck.k9.service.ShutdownReceiver; import com.fsck.k9.service.StorageGoneReceiver; import com.fsck.k9.widget.list.MessageListWidgetProvider; public class K9 extends Application { /** Loading Loading @@ -584,22 +585,37 @@ public class K9 extends Application { } } private void updateMailListWidget() { try { MessageListWidgetProvider.triggerMessageListWidgetUpdate(K9.this); } catch (RuntimeException e) { if (BuildConfig.DEBUG) { throw e; } else if (K9.DEBUG) { Log.e(LOG_TAG, "Error while updating message list widget", e); } } } @Override public void synchronizeMailboxRemovedMessage(Account account, String folder, Message message) { broadcastIntent(K9.Intents.EmailReceived.ACTION_EMAIL_DELETED, account, folder, message); updateUnreadWidget(); updateMailListWidget(); } @Override public void messageDeleted(Account account, String folder, Message message) { broadcastIntent(K9.Intents.EmailReceived.ACTION_EMAIL_DELETED, account, folder, message); updateUnreadWidget(); updateMailListWidget(); } @Override public void synchronizeMailboxNewMessage(Account account, String folder, Message message) { broadcastIntent(K9.Intents.EmailReceived.ACTION_EMAIL_RECEIVED, account, folder, message); updateUnreadWidget(); updateMailListWidget(); } @Override Loading @@ -607,6 +623,7 @@ public class K9 extends Application { int unreadMessageCount) { updateUnreadWidget(); updateMailListWidget(); // let observers know a change occurred Intent intent = new Intent(K9.Intents.EmailReceived.ACTION_REFRESH_OBSERVER, null); Loading
k9mail/src/main/java/com/fsck/k9/widget/list/MessageListRemoteViewFactory.java 0 → 100644 +209 −0 Original line number Diff line number Diff line package com.fsck.k9.widget.list; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Typeface; import android.net.Uri; import android.os.Binder; import android.support.v4.content.ContextCompat; import android.text.SpannableString; import android.text.style.StyleSpan; import android.view.View; import android.widget.RemoteViews; import android.widget.RemoteViewsService; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.provider.MessageProvider; public class MessageListRemoteViewFactory implements RemoteViewsService.RemoteViewsFactory { private static String[] MAIL_LIST_PROJECTIONS = { MessageProvider.MessageColumns.SENDER, MessageProvider.MessageColumns.SEND_DATE, MessageProvider.MessageColumns.SUBJECT, MessageProvider.MessageColumns.PREVIEW, MessageProvider.MessageColumns.UNREAD, MessageProvider.MessageColumns.HAS_ATTACHMENTS, MessageProvider.MessageColumns.URI }; private final Context context; private final Calendar calendar; private final ArrayList<MailItem> mailItems = new ArrayList<>(25); private boolean senderAboveSubject; private int readTextColor; private int unreadTextColor; public MessageListRemoteViewFactory(Context context) { this.context = context; calendar = Calendar.getInstance(); } @Override public void onCreate() { senderAboveSubject = K9.messageListSenderAboveSubject(); readTextColor = ContextCompat.getColor(context, R.color.message_list_widget_text_read); unreadTextColor = ContextCompat.getColor(context, R.color.message_list_widget_text_unread); } @Override public void onDataSetChanged() { long identityToken = Binder.clearCallingIdentity(); try { loadMessageList(); } finally { Binder.restoreCallingIdentity(identityToken); } } private void loadMessageList() { mailItems.clear(); Uri unifiedInboxUri = MessageProvider.CONTENT_URI.buildUpon().appendPath("inbox_messages").build(); Cursor cursor = context.getContentResolver().query(unifiedInboxUri, MAIL_LIST_PROJECTIONS, null, null, null); if (cursor == null) { return; } try { while (cursor.moveToNext()) { String sender = cursor.getString(0); long date = cursor.isNull(1) ? 0L : cursor.getLong(1); String subject = cursor.getString(2); String preview = cursor.getString(3); boolean unread = toBoolean(cursor.getString(4)); boolean hasAttachment = toBoolean(cursor.getString(5)); Uri viewUri = Uri.parse(cursor.getString(6)); mailItems.add(new MailItem(sender, date, subject, preview, unread, hasAttachment, viewUri)); } } finally { cursor.close(); } } @Override public void onDestroy() { // Implement interface } @Override public int getCount() { return mailItems.size(); } @Override public RemoteViews getViewAt(int position) { RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_list_item); MailItem item = mailItems.get(position); CharSequence sender = item.unread ? bold(item.sender) : item.sender; CharSequence subject = item.unread ? bold(item.subject) : item.subject; if (senderAboveSubject) { remoteView.setTextViewText(R.id.sender, sender); remoteView.setTextViewText(R.id.mail_subject, subject); } else { remoteView.setTextViewText(R.id.sender, subject); remoteView.setTextViewText(R.id.mail_subject, sender); } remoteView.setTextViewText(R.id.mail_date, item.getDateFormatted("%d %s")); remoteView.setTextViewText(R.id.mail_preview, item.preview); int textColor = item.getTextColor(); remoteView.setTextColor(R.id.sender, textColor); remoteView.setTextColor(R.id.mail_subject, textColor); remoteView.setTextColor(R.id.mail_date, textColor); remoteView.setTextColor(R.id.mail_preview, textColor); if (item.hasAttachment) { remoteView.setInt(R.id.attachment, "setVisibility", View.VISIBLE); } else { remoteView.setInt(R.id.attachment, "setVisibility", View.GONE); } Intent intent = new Intent(); intent.setData(item.uri); remoteView.setOnClickFillInIntent(R.id.mail_list_item, intent); return remoteView; } @Override public RemoteViews getLoadingView() { RemoteViews loadingView = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_loading); loadingView.setTextViewText(R.id.loadingText, context.getString(R.string.mail_list_widget_loading)); loadingView.setViewVisibility(R.id.loadingText, View.VISIBLE); return loadingView; } @Override public int getViewTypeCount() { return 2; } @Override public long getItemId(int position) { return position; } @Override public boolean hasStableIds() { return true; } private CharSequence bold(String text) { SpannableString spannableString = new SpannableString(text); spannableString.setSpan(new StyleSpan(Typeface.BOLD), 0, text.length(), 0); return spannableString; } private boolean toBoolean(String value) { return Boolean.valueOf(value); } private class MailItem { final long date; final String sender; final String preview; final String subject; final boolean unread; final boolean hasAttachment; final Uri uri; MailItem(String sender, long date, String subject, String preview, boolean unread, boolean hasAttachment, Uri viewUri) { this.sender = sender; this.date = date; this.preview = preview; this.subject = subject; this.unread = unread; this.uri = viewUri; this.hasAttachment = hasAttachment; } int getTextColor() { return unread ? unreadTextColor : readTextColor; } String getDateFormatted(String format) { calendar.setTimeInMillis(date); return String.format(format, calendar.get(Calendar.DAY_OF_MONTH), calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())); } } }
k9mail/src/main/java/com/fsck/k9/widget/list/MessageListWidgetProvider.java 0 → 100644 +85 −0 Original line number Diff line number Diff line package com.fsck.k9.widget.list; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.widget.RemoteViews; import com.fsck.k9.R; import com.fsck.k9.activity.MessageCompose; import com.fsck.k9.activity.MessageList; public class MessageListWidgetProvider extends AppWidgetProvider { private static String ACTION_UPDATE_MESSAGE_LIST = "UPDATE_MESSAGE_LIST"; public static void triggerMessageListWidgetUpdate(Context context) { Context appContext = context.getApplicationContext(); AppWidgetManager widgetManager = AppWidgetManager.getInstance(appContext); ComponentName widget = new ComponentName(appContext, MessageListWidgetProvider.class); int[] widgetIds = widgetManager.getAppWidgetIds(widget); Intent intent = new Intent(context, MessageListWidgetProvider.class); intent.setAction(ACTION_UPDATE_MESSAGE_LIST); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds); context.sendBroadcast(intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } } private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_layout); views.setTextViewText(R.id.folder, context.getString(R.string.integrated_inbox_title)); Intent intent = new Intent(context, MessageListWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); views.setRemoteAdapter(R.id.listView, intent); PendingIntent viewAction = viewActionTemplatePendingIntent(context); views.setPendingIntentTemplate(R.id.listView, viewAction); PendingIntent composeAction = composeActionPendingIntent(context); views.setOnClickPendingIntent(R.id.new_message, composeAction); appWidgetManager.updateAppWidget(appWidgetId, views); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); String action = intent.getAction(); if (action.equals(ACTION_UPDATE_MESSAGE_LIST)) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView); } } private PendingIntent viewActionTemplatePendingIntent(Context context) { Intent intent = new Intent(context, MessageList.class); intent.setAction(Intent.ACTION_VIEW); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } private PendingIntent composeActionPendingIntent(Context context) { Intent intent = new Intent(context, MessageCompose.class); intent.setAction(MessageCompose.ACTION_COMPOSE); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } }
k9mail/src/main/java/com/fsck/k9/widget/list/MessageListWidgetService.java 0 → 100644 +13 −0 Original line number Diff line number Diff line package com.fsck.k9.widget.list; import android.content.Intent; import android.widget.RemoteViewsService; public class MessageListWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new MessageListRemoteViewFactory(getApplicationContext()); } }