Add mail list widget

This commit is contained in:
denis mone 2016-11-10 02:55:45 +02:00 committed by cketti
parent fc90a8eadb
commit 6415f0c186
16 changed files with 550 additions and 2 deletions

View file

@ -277,6 +277,13 @@
</intent-filter>
</activity>
<activity android:name=".widget.list.MailListViewWidgetConfiguration">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name=".activity.UpgradeDatabases"
android:label="@string/upgrade_databases_title"/>
@ -356,6 +363,22 @@
android:resource="@xml/unread_widget_info"/>
</receiver>
<receiver android:name=".widget.list.MailListViewWidgetProvider"
android:icon="@drawable/mail_list_widget_icon"
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/mail_list_view_widget_layout_info"/>
</receiver>
<service android:name=".widget.list.MailListViewWidgetService"
android:enabled="true"
android:permission="android.permission.BIND_REMOTEVIEWS"/>
<service
android:name=".service.MailService"
android:enabled="true"/>

View file

@ -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.MailListViewWidgetProvider;
public class K9 extends Application {
/**
@ -584,22 +585,37 @@ public class K9 extends Application {
}
}
private void updateMailListWidget() {
try {
MailListViewWidgetProvider.updateMailViewList(K9.this);
} catch (Exception e) {
if (BuildConfig.DEBUG) {
throw e;
} else if (K9.DEBUG) {
Log.e(LOG_TAG, "Error whiile updating mail 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);

View file

@ -0,0 +1,181 @@
package com.fsck.k9.widget.list;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.*;
import android.os.Binder;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import com.fsck.k9.R;
import com.fsck.k9.provider.MessageProvider;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
public class MailListRemoteViewFactory implements RemoteViewsService.RemoteViewsFactory {
private static String [] MAIL_LIST_PROJECTIONS = {
MessageProvider.MessageColumns._ID,
MessageProvider.MessageColumns.SENDER,
MessageProvider.MessageColumns.SEND_DATE,
MessageProvider.MessageColumns.SUBJECT,
MessageProvider.MessageColumns.PREVIEW,
MessageProvider.MessageColumns.UNREAD,
MessageProvider.MessageColumns.HAS_ATTACHMENTS,
MessageProvider.MessageColumns.URI
};
private Context context;
private ArrayList<MailItem> mailItems;
private int count;
public MailListRemoteViewFactory(Context context) {
this.context = context;
}
@Override
public void onCreate() {
mailItems = new ArrayList<>(25);
}
@Override
public void onDataSetChanged() {
final long identityToken = Binder.clearCallingIdentity();
mailItems.clear();
Cursor cursor = context.getContentResolver().query(
MessageProvider.CONTENT_URI.buildUpon().appendPath("inbox_messages").build(),
MAIL_LIST_PROJECTIONS,
null,
null,
MessageProvider.MessageColumns.SEND_DATE + " DESC");
while (cursor.moveToNext()) {
final String id = cursor.getString(0);
final String sender = cursor.getString(1);
final String date = cursor.getString(2);
final String subject = cursor.getString(3);
final String preview = cursor.getString(4);
final String unread = cursor.getString(5);
final String hasAttachment = cursor.getString(6);
final String uri = cursor.getString(7);
mailItems.add(new MailItem(id, sender, date, subject, preview, unread, hasAttachment, uri));
}
count = cursor.getCount();
cursor.close();
Binder.restoreCallingIdentity(identityToken);
}
@Override
public void onDestroy() {
}
@Override
public int getCount() {
return count;
}
@Override
public RemoteViews getViewAt(int position) {
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.mail_list_item);
MailItem item = mailItems.get(position);
/* Populate the views from the mailItem object */
remoteView.setTextViewText(R.id.sender, item.sender);
remoteView.setTextViewText(R.id.mail_subject, item.subject);
remoteView.setTextViewText(R.id.mail_date, item.getDateFormatted("%d %s"));
remoteView.setTextViewText(R.id.mail_preview, item.preview);
int textColor = item.getColor();
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.putExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, item.uri);
remoteView.setOnClickFillInIntent(R.id.mail_list_item, intent);
return remoteView;
}
@Override
public RemoteViews getLoadingView() {
RemoteViews loadingView = new RemoteViews(context.getPackageName(), R.layout.mail_list_loading_view);
loadingView.setTextViewText(R.id.loadingText, "Loading emails");
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 static class MailItem {
private String id;
private String date;
private String sender;
private String preview;
private String subject;
private String unread;
private String hasAttachment;
private String uri;
private static Calendar cl = Calendar.getInstance();
public MailItem(String id, String sender, String date, String subject,
String preview, String unread, String hasAttachment, String uri) {
this.id = id;
this.sender = sender;
this.date = date;
this.preview = preview;
this.subject = subject;
this.unread = unread;
this.uri = uri;
this.hasAttachment = hasAttachment;
}
public int getColor() {
if (Boolean.valueOf(unread)) {
return Color.BLACK;
} else {
/* light_black */
return Color.parseColor("#444444");
}
}
public String getDateFormatted(String format) {
// set default format if null is passed
if (format.isEmpty()) {
format = "%d %s";
}
cl.setTimeInMillis(Long.valueOf(date));
return String.format(format,
cl.get(Calendar.DAY_OF_MONTH),
cl.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()));
}
public boolean hasAttachment() {
return Boolean.valueOf(hasAttachment);
}
}
}

View file

@ -0,0 +1,79 @@
package com.fsck.k9.widget.list;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import com.fsck.k9.BaseAccount;
import com.fsck.k9.R;
import com.fsck.k9.activity.AccountList;
public class MailListViewWidgetConfiguration extends AccountList {
private static final String PREFS_NAME = "mail_list_view_widget_configuration.xml";
private static final String PREF_PREFIX_KEY = "mail_list_view_widget.";
private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private static void saveAccountUuid(Context context, int appWidgetId, String accountUuid) {
SharedPreferences.Editor editor =
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit();
editor.putString(PREF_PREFIX_KEY + appWidgetId, accountUuid);
editor.commit();
}
public static String getAccountUuid(Context context, int appWidgetId) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
String accountUuid = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null);
return accountUuid;
}
public static void deleteWidgetConfiguration(Context context, int appWidgetId) {
SharedPreferences.Editor editor = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit();
editor.remove(PREF_PREFIX_KEY + appWidgetId);
editor.commit();
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Find the widget ID from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If they gave us an intent without the widget ID, just bail.
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
return;
}
setTitle(R.string.mail_list_view_select_account);
}
@Override
protected boolean displaySpecialAccounts() {
return true;
}
@Override
protected void onAccountSelected(BaseAccount account) {
// Save widget configuration
String accountUuid = account.getUuid();
saveAccountUuid(this, appWidgetId, accountUuid);
// Update widget
Context context = getApplicationContext();
MailListViewWidgetProvider.updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetId, accountUuid);
// Let the caller know that the configuration was successful
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
}

View file

@ -0,0 +1,109 @@
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.Account;
import com.fsck.k9.Preferences;
import com.fsck.k9.R;
import com.fsck.k9.activity.MessageCompose;
import com.fsck.k9.activity.MessageList;
public class MailListViewWidgetProvider extends AppWidgetProvider {
public static final String PACKAGE_NAME = "com.fsck.k9";
public static String ACTION_VIEW_MAIL_ITEM = PACKAGE_NAME + ".provider.ACTION_VIEW_MAIL_ITEM";
public static String ACTION_COMPOSE_EMAIL = PACKAGE_NAME + ".provider.ACTION_COMPOSE_EMAIL";
public static void updateMailViewList(Context context) {
Context appContext = context.getApplicationContext();
AppWidgetManager widgetManager = AppWidgetManager.getInstance(appContext);
ComponentName widget = new ComponentName(appContext, MailListViewWidgetProvider.class);
int [] widgetIds = widgetManager.getAppWidgetIds(widget);
Intent intent = new Intent(context, MailListViewWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds);
context.sendBroadcast(intent);
}
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, String acc) {
CharSequence widgetText = context.getString(R.string.mail_list_widget_text);
Account account = Preferences.getPreferences(context).getAccount(acc);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.mail_list_view_widget_layout);
views.setRemoteAdapter(R.id.listView, new Intent(context, MailListViewWidgetService.class));
views.setTextViewText(R.id.folder, account.getInboxFolderName());
views.setTextViewText(R.id.mail_address, account.getEmail());
Intent intent = new Intent(context, MailListViewWidgetService.class)
.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
views.setRemoteAdapter(R.id.listView, intent);
Intent clickIntent = new Intent(context, MailListViewWidgetProvider.class);
clickIntent.setPackage(PACKAGE_NAME);
clickIntent.setAction(ACTION_VIEW_MAIL_ITEM);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, MessageList.REQUEST_MASK_PENDING_INTENT,
clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setPendingIntentTemplate(R.id.listView, pendingIntent);
Intent composeIntent = new Intent(context, MailListViewWidgetProvider.class);
composeIntent.setPackage(PACKAGE_NAME);
composeIntent.setAction(ACTION_COMPOSE_EMAIL);
composeIntent.putExtra(MessageCompose.EXTRA_ACCOUNT, acc);
PendingIntent newMailIntent = PendingIntent.getBroadcast(context, 0, composeIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// Add intent for composing a new message
views.setOnClickPendingIntent(R.id.new_message, newMailIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
String acc;
for (int widgId : appWidgetIds) {
acc = MailListViewWidgetConfiguration.getAccountUuid(context, widgId);
updateAppWidget(context, appWidgetManager, widgId, acc);
}
}
@Override
public void onReceive(Context context, Intent intent) {
// an intent from an item on the listview. get the uri and launch the MessageList activity
if (intent.getAction().equals(ACTION_VIEW_MAIL_ITEM)) {
Intent viewMailIntent = new Intent(context, MessageList.class);
viewMailIntent.setAction(Intent.ACTION_VIEW);
viewMailIntent.setData(Uri.parse(intent.getStringExtra(AppWidgetManager.EXTRA_CUSTOM_INFO)));
viewMailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(viewMailIntent);
} else if (intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) {
AppWidgetManager.getInstance(context)
.notifyAppWidgetViewDataChanged(intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS),
R.id.listView);
} else if (intent.getAction().equals(ACTION_COMPOSE_EMAIL)) {
Intent newMessage = new Intent(context, MessageCompose.class)
.putExtra(MessageCompose.EXTRA_ACCOUNT, intent.getStringExtra(MessageCompose.EXTRA_ACCOUNT))
.setAction(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newMessage);
}
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
for (int widgId : appWidgetIds) {
MailListViewWidgetConfiguration.deleteWidgetConfiguration(context, widgId);
}
}
}

View file

@ -0,0 +1,13 @@
package com.fsck.k9.widget.list;
import android.content.Intent;
import android.widget.RemoteViewsService;
public class MailListViewWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new MailListRemoteViewFactory(this.getApplicationContext());
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mail_list_item"
android:padding="@dimen/widget_padding"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/sender"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_gravity="start"
android:textSize="16sp"/>
<ImageView android:id="@+id/attachment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_email_attachment_small"
android:visibility="gone"
android:layout_centerInParent="true"
android:layout_toLeftOf="@+id/mail_date"
android:layout_toStartOf="@+id/mail_date"
android:layout_alignBottom="@+id/mail_date"/>
<TextView android:id="@+id/mail_date"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBaseline="@+id/sender"
android:layout_centerVertical="true"/>
<TextView android:id="@+id/mail_subject"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:paddingBottom="2dp"
android:singleLine="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/sender"/>
<TextView android:id="@+id/mail_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="13sp"
android:singleLine="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/mail_subject"/>
</RelativeLayout>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/loadingText" android:textColor="@android:color/black" android:textSize="18sp" android:layout_width="match_parent" android:layout_height="match_parent"/>
</LinearLayout>

View file

@ -0,0 +1,48 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/top_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="@dimen/widget_padding"
android:background="@color/light_grey">
<TextView android:id="@+id/folder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView android:id="@+id/mail_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:layout_alignParentLeft="true"
android:layout_below="@+id/folder"/>
<ImageButton android:id="@+id/new_message"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_compose_dark"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/mail_address"
style="?android:attr/borderlessButtonStyle"/>
</RelativeLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white">
<ListView android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:dividerHeight="1dp"
android:divider="@color/light_grey"/>
</LinearLayout>
</LinearLayout>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="message_list_item_footer_background">#eeeeee</color>
<color name="light_black">#444</color>
<color name="light_black">#444444</color>
<color name="light_grey">#737373</color>
</resources>

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="button_minWidth">100sp</dimen>
<dimen name="widget_padding">8dp</dimen>
</resources>

View file

@ -1218,4 +1218,6 @@ Please submit bug reports, contribute new features and ask questions at
<string name="apg">APG</string>
<string name="no_crypto_provider_see_global">No OpenPGP app configured, see global settings!</string>
<string name="mail_list_widget_text">K-9 Message List</string>
<string name="mail_list_view_select_account">Select account to list e-mails for</string>
</resources>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="250dp"
android:minHeight="180dp"
android:updatePeriodMillis="86400000"
android:previewImage="@drawable/mail_list_widget_icon"
android:configure="com.fsck.k9.widget.list.MailListViewWidgetConfiguration"
android:initialLayout="@layout/mail_list_view_widget_layout"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard"
android:initialKeyguardLayout="@layout/mail_list_view_widget_layout">
</appwidget-provider>