Read all contacts at startup

pull/156/head
M66B 5 years ago
parent 01f5e07deb
commit aa806b7ce4

@ -1591,7 +1591,6 @@ About each four hours FairEmail runs a cleanup job that:
* Removes old image files * Removes old image files
* Removes old local contacts * Removes old local contacts
* Removes old log entries * Removes old log entries
* Updates contact photos of messages
You can see when the last cleanup was performed at the bottom of the advanced options. You can see when the last cleanup was performed at the bottom of the advanced options.

@ -33,6 +33,7 @@ import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.DeadSystemException; import android.os.DeadSystemException;
import android.os.Handler;
import android.os.RemoteException; import android.os.RemoteException;
import android.webkit.CookieManager; import android.webkit.CookieManager;
@ -91,10 +92,14 @@ public class ApplicationEx extends Application {
}); });
upgrade(this); upgrade(this);
createNotificationChannels(); createNotificationChannels();
if (Helper.hasWebView(this)) if (Helper.hasWebView(this))
CookieManager.getInstance().setAcceptCookie(false); CookieManager.getInstance().setAcceptCookie(false);
MessageHelper.setSystemProperties(); MessageHelper.setSystemProperties();
ContactInfo.init(this, new Handler());
Core.init(this); Core.init(this);
} }

@ -23,6 +23,7 @@ import android.Manifest;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
@ -34,6 +35,7 @@ import android.graphics.PorterDuffXfermode;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.net.Uri; import android.net.Uri;
import android.os.Handler;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import android.util.TypedValue; import android.util.TypedValue;
@ -43,6 +45,7 @@ import java.io.InputStream;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.mail.Address; import javax.mail.Address;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
@ -54,10 +57,10 @@ public class ContactInfo {
private Uri lookupUri; private Uri lookupUri;
private long time; private long time;
private static Map<String, LookupInfo> emailLookupInfo = new HashMap<>(); private static Object lock = new Object();
private static Map<String, Uri> emailLookup = new ConcurrentHashMap<>();
private static Map<String, ContactInfo> emailContactInfo = new HashMap<>(); private static Map<String, ContactInfo> emailContactInfo = new HashMap<>();
private static final long CACHE_LOOKUP_DURATION = 120 * 60 * 1000L;
private static final long CACHE_CONTACT_DURATION = 60 * 1000L; private static final long CACHE_CONTACT_DURATION = 60 * 1000L;
private ContactInfo() { private ContactInfo() {
@ -93,9 +96,6 @@ public class ContactInfo {
} }
static void clearCache() { static void clearCache() {
synchronized (emailLookupInfo) {
emailLookupInfo.clear();
}
synchronized (emailContactInfo) { synchronized (emailContactInfo) {
emailContactInfo.clear(); emailContactInfo.clear();
} }
@ -214,65 +214,62 @@ public class ContactInfo {
return info; return info;
} }
static Uri getLookupUri(Context context, Address[] addresses) { static void init(final Context context, Handler handler) {
if (!Helper.hasPermission(context, Manifest.permission.READ_CONTACTS)) if (Helper.hasPermission(context, Manifest.permission.READ_CONTACTS)) {
return null; ContentObserver observer = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.i("Contact changed uri=" + uri);
emailLookup = getEmailLookup(context);
}
};
if (addresses == null || addresses.length == 0) emailLookup = getEmailLookup(context);
Uri uri = ContactsContract.CommonDataKinds.Email.CONTENT_URI;
Log.i("Observing uri=" + uri);
context.getContentResolver().registerContentObserver(uri, true, observer);
}
}
static Uri getLookupUri(Context context, Address[] addresses) {
if (addresses == null)
return null; return null;
InternetAddress address = (InternetAddress) addresses[0];
synchronized (emailLookupInfo) { for (Address from : addresses) {
LookupInfo info = emailLookupInfo.get(address.getAddress()); String email = ((InternetAddress) from).getAddress();
if (info != null && !info.isExpired()) if (emailLookup.containsKey(email))
return info.uri; return emailLookup.get(email);
} }
try { return null;
}
private static Map<String, Uri> getEmailLookup(Context context) {
Map<String, Uri> all = new ConcurrentHashMap<>();
if (Helper.hasPermission(context, Manifest.permission.READ_CONTACTS)) {
ContentResolver resolver = context.getContentResolver(); ContentResolver resolver = context.getContentResolver();
try (Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, try (Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
new String[]{ new String[]{
ContactsContract.CommonDataKinds.Photo.CONTACT_ID, ContactsContract.CommonDataKinds.Photo.CONTACT_ID,
ContactsContract.Contacts.LOOKUP_KEY ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.CommonDataKinds.Email.ADDRESS
}, },
ContactsContract.CommonDataKinds.Email.ADDRESS + " = ?", ContactsContract.CommonDataKinds.Email.ADDRESS + " <> ''",
new String[]{ null, null)) {
address.getAddress() while (cursor != null && cursor.moveToNext()) {
}, null)) { long contactId = cursor.getLong(0);
String lookupKey = cursor.getString(1);
Uri uri = null; String email = cursor.getString(2);
if (cursor != null && cursor.moveToNext()) {
int colContactId = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.CONTACT_ID); Uri uri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
int colLookupKey = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY); all.put(email, uri);
long contactId = cursor.getLong(colContactId);
String lookupKey = cursor.getString(colLookupKey);
uri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
} }
LookupInfo info = new LookupInfo();
info.uri = uri;
info.time = new Date().getTime();
synchronized (emailLookupInfo) {
emailLookupInfo.put(address.getAddress(), info);
}
return info.uri;
} }
} catch (Throwable ex) {
Log.e(ex);
return null;
} }
}
private static class LookupInfo {
private Uri uri;
private long time;
private boolean isExpired() { Log.i("Read email/uri=" + all.size());
return (new Date().getTime() - time > CACHE_LOOKUP_DURATION); return all;
}
} }
} }

@ -1383,6 +1383,14 @@ class Core {
Log.i(folder.name + " updated id=" + message.id + " uid=" + message.uid + " unbrowse"); Log.i(folder.name + " updated id=" + message.id + " uid=" + message.uid + " unbrowse");
} }
Uri uri = ContactInfo.getLookupUri(context, message.from);
String avatar = (uri == null ? null : uri.toString());
if (!Objects.equals(message.avatar, avatar)) {
update = true;
message.avatar = avatar;
Log.i(folder.name + " updated id=" + message.id + " uid=" + message.uid + " avatar=" + avatar);
}
if (update) if (update)
try { try {
db.beginTransaction(); db.beginTransaction();

@ -21,7 +21,6 @@ package eu.faircode.email;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build; import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -39,7 +38,6 @@ import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class WorkerCleanup extends Worker { public class WorkerCleanup extends Worker {
@ -146,33 +144,6 @@ public class WorkerCleanup extends Worker {
Log.i("Cleanup log"); Log.i("Cleanup log");
int logs = db.log().deleteLogs(now - KEEP_LOG_DURATION); int logs = db.log().deleteLogs(now - KEEP_LOG_DURATION);
Log.i("Deleted logs=" + logs); Log.i("Deleted logs=" + logs);
Log.i("Update lookup URIs");
ContactInfo.clearCache();
List<EntityFolder> folders = db.folder().getSynchronizingFolders();
for (EntityFolder folder : folders) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, -folder.sync_days);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long sync_time = cal.getTimeInMillis();
if (sync_time < 0)
sync_time = 0;
Log.i("Update lookup URIs " + folder.name + " before " + new Date(sync_time));
List<TupleMessageLookup> avatars = db.message().getAvatars(folder.id, sync_time);
for (TupleMessageLookup message : avatars) {
Uri uri = (message.avatar == null ? null : Uri.parse(message.avatar));
Uri lookup = ContactInfo.getLookupUri(context, message.from);
if (!Objects.equals(uri, lookup)) {
Log.i("Updating email=" + MessageHelper.formatAddresses(message.from) + " uri=" + lookup);
db.message().setMessageAvatar(message.id, lookup == null ? null : lookup.toString());
}
}
}
Log.i("Updated lookup URIs");
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(ex); Log.e(ex);
} finally { } finally {

Loading…
Cancel
Save