Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1b2d0a3 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #2255 from k9mail/message_list_widget

Message list widget
parents fc90a8ea 0a3a9143
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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"/>
+17 −0
Original line number Diff line number Diff line
@@ -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 {
    /**
@@ -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
@@ -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);
+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()));
        }
    }
}
+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);
    }
}
+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