mirror of
https://github.com/moparisthebest/k-9
synced 2025-02-07 18:50:11 -05:00
Update issue 1623
Message retrieval: - Use the given projection for the cursor result instead of always using a predefined projection. Extraction logic is now in dedicated classes for easy extension. - Added BaseColumns._ID & BaseColumns._COUNT columns. - Deprecated "id" column since it's not a reliable identifier (it's an incremential value generated at query() time)
This commit is contained in:
parent
3503355b2e
commit
296ab4f2be
@ -3,6 +3,7 @@ package com.fsck.k9.provider;
|
|||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -71,6 +72,16 @@ public class MessageProvider extends ContentProvider
|
|||||||
* <P>Type: TEXT</P>
|
* <P>Type: TEXT</P>
|
||||||
*/
|
*/
|
||||||
String PREVIEW = "preview";
|
String PREVIEW = "preview";
|
||||||
|
|
||||||
|
String ACCOUNT = "account";
|
||||||
|
String URI = "uri";
|
||||||
|
String DELETE_URI = "delUri";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated the field value is misnamed/misleading - present for compatibility purpose only. To be removed.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
String INCREMENT = "id";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface QueryHandler
|
protected interface QueryHandler
|
||||||
@ -96,6 +107,119 @@ public class MessageProvider extends ContentProvider
|
|||||||
String selection, String[] selectionArgs, String sortOrder) throws Exception;
|
String selection, String[] selectionArgs, String sortOrder) throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a value from an object.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* @param <K>
|
||||||
|
*/
|
||||||
|
public static interface FieldExtractor<T, K>
|
||||||
|
{
|
||||||
|
K getField(T source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the {@link LocalStore.LocalMessage#getId() ID} from the given
|
||||||
|
* {@link MessageInfoHolder}. The underlying {@link Message} is expected to
|
||||||
|
* be a {@link LocalStore.LocalMessage}.
|
||||||
|
*/
|
||||||
|
public static class IdExtractor implements FieldExtractor<MessageInfoHolder, Long>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Long getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return ((LocalStore.LocalMessage) source.message).getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class CountExtractor<T> implements FieldExtractor<T, Integer>
|
||||||
|
{
|
||||||
|
private Integer mCount;
|
||||||
|
public CountExtractor(final int count)
|
||||||
|
{
|
||||||
|
mCount = count;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Integer getField(final T source)
|
||||||
|
{
|
||||||
|
return mCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class SubjectExtractor implements FieldExtractor<MessageInfoHolder, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return source.subject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class SendDateExtractor implements FieldExtractor<MessageInfoHolder, Long>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Long getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return source.message.getSentDate().getTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class PreviewExtractor implements FieldExtractor<MessageInfoHolder, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return source.preview;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class UriExtractor implements FieldExtractor<MessageInfoHolder, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return source.uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class DeleteUriExtractor implements FieldExtractor<MessageInfoHolder, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
final Message message = source.message;
|
||||||
|
return CONTENT_URI + "/delete_message/"
|
||||||
|
+ message.getFolder().getAccount().getAccountNumber() + "/"
|
||||||
|
+ message.getFolder().getName() + "/" + message.getUid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class SenderExtractor implements FieldExtractor<MessageInfoHolder, CharSequence>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public CharSequence getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return source.sender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class AccountExtractor implements FieldExtractor<MessageInfoHolder, String>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return source.message.getFolder().getAccount().getDescription();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated having an incremential value has no real interest,
|
||||||
|
* implemented for compatibility only
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
// TODO remove
|
||||||
|
public static class IncrementExtractor implements FieldExtractor<MessageInfoHolder, Integer>
|
||||||
|
{
|
||||||
|
private int count = 0;
|
||||||
|
@Override
|
||||||
|
public Integer getField(final MessageInfoHolder source)
|
||||||
|
{
|
||||||
|
return count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve messages from the integrated inbox.
|
* Retrieve messages from the integrated inbox.
|
||||||
*/
|
*/
|
||||||
@ -124,8 +248,6 @@ public class MessageProvider extends ContentProvider
|
|||||||
*/
|
*/
|
||||||
protected MatrixCursor getMessages(final String[] projection) throws InterruptedException
|
protected MatrixCursor getMessages(final String[] projection) throws InterruptedException
|
||||||
{
|
{
|
||||||
// TODO use the given projection if prevent
|
|
||||||
final MatrixCursor cursor = new MatrixCursor(DEFAULT_MESSAGE_PROJECTION);
|
|
||||||
final BlockingQueue<List<MessageInfoHolder>> queue = new SynchronousQueue<List<MessageInfoHolder>>();
|
final BlockingQueue<List<MessageInfoHolder>> queue = new SynchronousQueue<List<MessageInfoHolder>>();
|
||||||
|
|
||||||
// new code for integrated inbox, only execute this once as it will be processed afterwards via the listener
|
// new code for integrated inbox, only execute this once as it will be processed afterwards via the listener
|
||||||
@ -141,29 +263,94 @@ public class MessageProvider extends ContentProvider
|
|||||||
Collections.sort(holders, new MessageList.ReverseComparator<MessageInfoHolder>(
|
Collections.sort(holders, new MessageList.ReverseComparator<MessageInfoHolder>(
|
||||||
new MessageList.DateComparator()));
|
new MessageList.DateComparator()));
|
||||||
|
|
||||||
int id = -1;
|
final String[] projectionToUse;
|
||||||
|
if (projection == null)
|
||||||
|
{
|
||||||
|
projectionToUse = DEFAULT_MESSAGE_PROJECTION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
projectionToUse = projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LinkedHashMap<String, FieldExtractor<MessageInfoHolder, ?>> extractors = resolveMessageExtractors(projectionToUse, holders.size());
|
||||||
|
final int fieldCount = extractors.size();
|
||||||
|
|
||||||
|
final String[] actualProjection = extractors.keySet().toArray(new String[fieldCount]);
|
||||||
|
final MatrixCursor cursor = new MatrixCursor(actualProjection);
|
||||||
|
|
||||||
for (final MessageInfoHolder holder : holders)
|
for (final MessageInfoHolder holder : holders)
|
||||||
{
|
{
|
||||||
final Message message = holder.message;
|
final Object[] o = new Object[fieldCount];
|
||||||
id++;
|
|
||||||
|
|
||||||
cursor.addRow(new Object[]
|
int i = 0;
|
||||||
{
|
for (final FieldExtractor<MessageInfoHolder, ?> extractor : extractors.values())
|
||||||
id,
|
{
|
||||||
message.getSentDate().getTime(),
|
o[i] = extractor.getField(holder);
|
||||||
holder.sender,
|
i += 1;
|
||||||
holder.subject,
|
}
|
||||||
holder.preview,
|
|
||||||
holder.account,
|
cursor.addRow(o);
|
||||||
holder.uri,
|
|
||||||
CONTENT_URI + "/delete_message/"
|
|
||||||
+ message.getFolder().getAccount().getAccountNumber() + "/"
|
|
||||||
+ message.getFolder().getName() + "/" + message.getUid()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns LinkedHashMap (rather than Map) to emphasize the inner element ordering
|
||||||
|
protected LinkedHashMap<String, FieldExtractor<MessageInfoHolder, ?>> resolveMessageExtractors(final String[] projection, int count)
|
||||||
|
{
|
||||||
|
final LinkedHashMap<String, FieldExtractor<MessageInfoHolder, ?>> extractors = new LinkedHashMap<String, FieldExtractor<MessageInfoHolder, ?>>();
|
||||||
|
|
||||||
|
for (final String field : projection)
|
||||||
|
{
|
||||||
|
if (extractors.containsKey(field))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (MessageColumns._ID.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new IdExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns._COUNT.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new CountExtractor<MessageInfoHolder>(count));
|
||||||
|
}
|
||||||
|
else if (MessageColumns.SUBJECT.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new SubjectExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.SENDER.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new SenderExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.SEND_DATE.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new SendDateExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.PREVIEW.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new PreviewExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.URI.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new UriExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.DELETE_URI.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new DeleteUriExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.ACCOUNT.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new AccountExtractor());
|
||||||
|
}
|
||||||
|
else if (MessageColumns.INCREMENT.equals(field))
|
||||||
|
{
|
||||||
|
extractors.put(field, new IncrementExtractor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractors;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -659,9 +846,9 @@ public class MessageProvider extends ContentProvider
|
|||||||
MessageColumns.SENDER,
|
MessageColumns.SENDER,
|
||||||
MessageColumns.SUBJECT,
|
MessageColumns.SUBJECT,
|
||||||
MessageColumns.PREVIEW,
|
MessageColumns.PREVIEW,
|
||||||
"account",
|
MessageColumns.ACCOUNT,
|
||||||
"uri",
|
MessageColumns.URI,
|
||||||
"delUri"
|
MessageColumns.DELETE_URI
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user