Get contact info in real-time, refactoring, improvements

This commit is contained in:
M66B 2019-01-19 09:48:45 +00:00
parent a14c8e8f2b
commit f821458aa9
10 changed files with 102 additions and 105 deletions

View File

@ -1040,7 +1040,6 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
Bundle args = new Bundle();
args.putLong("account", intent.getLongExtra("account", -1));
args.putLong("folder", intent.getLongExtra("folder", -1));
args.putBoolean("outgoing", intent.getBooleanExtra("outgoing", false));
FragmentMessages fragment = new FragmentMessages();
fragment.setArguments(args);

View File

@ -214,8 +214,7 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
lbm.sendBroadcast(
new Intent(ActivityView.ACTION_VIEW_MESSAGES)
.putExtra("account", folder.account)
.putExtra("folder", folder.id)
.putExtra("outgoing", folder.isOutgoing()));
.putExtra("folder", folder.id));
}
@Override

View File

@ -113,7 +113,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private LayoutInflater inflater;
private LifecycleOwner owner;
private ViewType viewType;
private boolean outgoing;
private boolean compact;
private int zoom;
private boolean internet;
@ -410,6 +409,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvError.setAlpha(message.duplicate ? Helper.LOW_LIGHT : 1.0f);
}
boolean outgoing = (viewType != ViewType.THREAD && EntityFolder.isOutgoing(message.folderType));
if (!outgoing && (avatars || identicons)) {
Bundle aargs = new Bundle();
aargs.putLong("id", message.id);
@ -417,45 +418,73 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
if (message.from != null && message.from.length > 0)
aargs.putString("from", message.from[0].toString());
new SimpleTask<Drawable>() {
new SimpleTask<ContactInfo>() {
@Override
protected void onPreExecute(Bundle args) {
ivAvatar.setTag(message.id);
ivAvatar.setVisibility(View.INVISIBLE);
tvFrom.setTag(message.id);
}
@Override
protected Drawable onExecute(Context context, Bundle args) {
protected ContactInfo onExecute(Context context, Bundle args) {
String uri = args.getString("uri");
if (avatars && uri != null)
ContactInfo info = new ContactInfo();
ContentResolver resolver = context.getContentResolver();
if (contacts && avatars && uri != null)
try {
ContentResolver resolver = context.getContentResolver();
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(resolver, Uri.parse(uri));
if (is != null)
return Drawable.createFromStream(is, "avatar");
info.avatar = Drawable.createFromStream(is, "avatar");
} catch (SecurityException ex) {
Log.e(ex);
}
String from = args.getString("from");
if (identicons && from != null)
return new BitmapDrawable(
if (info.avatar == null && identicons && from != null)
info.avatar = new BitmapDrawable(
context.getResources(),
Identicon.generate(from, dp24, 5, "light".equals(theme)));
return null;
if (contacts && uri != null) {
Cursor cursor = null;
try {
cursor = resolver.query(
Uri.parse(uri),
new String[]{ContactsContract.Contacts.DISPLAY_NAME},
null, null, null);
if (cursor != null && cursor.moveToNext())
info.displayName = cursor.getString(0);
} finally {
if (cursor != null)
cursor.close();
}
}
return info;
}
@Override
protected void onExecuted(Bundle args, Drawable avatar) {
if ((long) ivAvatar.getTag() == args.getLong("id")) {
if (avatar == null)
protected void onExecuted(Bundle args, ContactInfo info) {
long id = args.getLong("id");
if ((long) ivAvatar.getTag() == id) {
if (info.avatar == null)
ivAvatar.setImageResource(R.drawable.baseline_person_24);
else
ivAvatar.setImageDrawable(avatar);
ivAvatar.setImageDrawable(info.avatar);
ivAvatar.setVisibility(View.VISIBLE);
} else
Log.i("Skipping avatar");
if ((long) tvFrom.getTag() == id) {
if (info.displayName != null) {
Log.i("Using contact name=" + info.displayName);
tvFrom.setText(info.displayName);
}
}
}
@Override
@ -2003,12 +2032,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}
AdapterMessage(Context context, LifecycleOwner owner,
ViewType viewType, boolean outgoing, boolean compact, int zoom, IProperties properties) {
ViewType viewType, boolean compact, int zoom, IProperties properties) {
this.context = context;
this.owner = owner;
this.inflater = LayoutInflater.from(context);
this.viewType = viewType;
this.outgoing = outgoing;
this.compact = compact;
this.zoom = zoom;
this.internet = (Helper.isMetered(context, false) != null);
@ -2175,6 +2203,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
return key;
}
private class ContactInfo {
Drawable avatar;
String displayName;
}
interface IProperties {
void setValue(String name, long id, boolean enabled);

View File

@ -119,8 +119,7 @@ public class AdapterOperation extends RecyclerView.Adapter<AdapterOperation.View
lbm.sendBroadcast(
new Intent(ActivityView.ACTION_VIEW_MESSAGES)
.putExtra("account", folder.account)
.putExtra("folder", folder.id)
.putExtra("outgoing", folder.isOutgoing()));
.putExtra("folder", folder.id));
}
@Override

View File

@ -29,7 +29,6 @@ import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -151,8 +150,7 @@ public class EntityMessage implements Serializable {
public String error; // volatile
public Long last_attempt; // send
private static final Map<String, ContactInfo> emailContactInfo = new HashMap<>();
private static final long MAX_CACHED_CONTACTINFO_AGE = 20 * 60 * 1000L; // milliseconds
private static final Map<String, Uri> emailLookupUri = new HashMap<>();
static String generateMessageId() {
StringBuilder sb = new StringBuilder();
@ -212,88 +210,58 @@ public class EntityMessage implements Serializable {
return new File(dir, Long.toString(id));
}
private class ContactInfo {
Uri lookupUri;
String displayName;
long time;
static String getLookupUri(Context context, Address[] froms) {
if (froms == null)
return null;
ContactInfo(Uri lookupUri, String displayName) {
this.lookupUri = lookupUri;
this.displayName = displayName;
this.time = new Date().getTime();
}
boolean isValid() {
long age = new Date().getTime() - this.time;
return age < MAX_CACHED_CONTACTINFO_AGE;
}
}
boolean setContactInfo(Context context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
== PackageManager.PERMISSION_GRANTED) {
this.avatar = null;
!= PackageManager.PERMISSION_GRANTED)
return null;
try {
if (this.from != null)
for (Address from : this.from) {
InternetAddress address = ((InternetAddress) from);
String email = address.getAddress();
try {
for (Address from : froms) {
String email = ((InternetAddress) from).getAddress();
synchronized (emailContactInfo) {
ContactInfo info = emailContactInfo.get(email);
if (info != null && info.isValid()) {
this.avatar = info.lookupUri.toString();
if (!TextUtils.isEmpty(info.displayName))
address.setPersonal(info.displayName);
return true;
}
synchronized (emailLookupUri) {
Uri lookupUri = emailLookupUri.get(email);
if (lookupUri != null)
return lookupUri.toString();
}
Cursor cursor = null;
try {
ContentResolver resolver = context.getContentResolver();
cursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
new String[]{
ContactsContract.CommonDataKinds.Photo.CONTACT_ID,
ContactsContract.Contacts.LOOKUP_KEY
},
ContactsContract.CommonDataKinds.Email.ADDRESS + " = ?",
new String[]{email}, null);
if (cursor != null && cursor.moveToNext()) {
int colContactId = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.CONTACT_ID);
int colLookupKey = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
long contactId = cursor.getLong(colContactId);
String lookupKey = cursor.getString(colLookupKey);
Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
synchronized (emailLookupUri) {
emailLookupUri.put(email, lookupUri);
}
Cursor cursor = null;
try {
ContentResolver resolver = context.getContentResolver();
cursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
new String[]{
ContactsContract.CommonDataKinds.Photo.CONTACT_ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME
},
ContactsContract.CommonDataKinds.Email.ADDRESS + " = ?",
new String[]{email}, null);
if (cursor != null && cursor.moveToNext()) {
int colContactId = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.CONTACT_ID);
int colLookupKey = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
int colDisplayName = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
long contactId = cursor.getLong(colContactId);
String lookupKey = cursor.getString(colLookupKey);
String displayName = cursor.getString(colDisplayName);
Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
this.avatar = lookupUri.toString();
if (!TextUtils.isEmpty(displayName))
address.setPersonal(displayName);
synchronized (emailContactInfo) {
emailContactInfo.put(email, new ContactInfo(lookupUri, displayName));
}
return true;
}
} finally {
if (cursor != null)
cursor.close();
}
return lookupUri.toString();
}
} catch (Throwable ex) {
Log.e(ex);
} finally {
if (cursor != null)
cursor.close();
}
}
} catch (Throwable ex) {
Log.e(ex);
}
return false;
return null;
}
static void snooze(Context context, long id, Long wakeup) {

View File

@ -214,7 +214,7 @@ public class EntityRule {
reply.subject = context.getString(R.string.title_subject_reply, message.subject == null ? "" : message.subject);
reply.sender = MessageHelper.getSortKey(reply.from);
reply.received = new Date().getTime();
reply.setContactInfo(context);
reply.avatar = EntityMessage.getLookupUri(context, reply.from);
reply.id = db.message().insertMessage(reply);
reply.write(context, body);
db.message().setMessageContent(reply.id, true, HtmlHelper.getPreview(body));

View File

@ -1551,7 +1551,7 @@ public class FragmentCompose extends FragmentBase {
result.draft.sender = MessageHelper.getSortKey(result.draft.from);
result.draft.received = new Date().getTime();
result.draft.setContactInfo(context);
result.draft.avatar = EntityMessage.getLookupUri(context, result.draft.from);
result.draft.id = db.message().insertMessage(result.draft);
result.draft.write(context, body == null ? "" : body);

View File

@ -101,7 +101,6 @@ public class FragmentMessages extends FragmentBase {
private long account;
private long folder;
private boolean outgoing;
private String thread;
private long id;
private String search;
@ -156,7 +155,6 @@ public class FragmentMessages extends FragmentBase {
Bundle args = getArguments();
account = args.getLong("account", -1);
folder = args.getLong("folder", -1);
outgoing = args.getBoolean("outgoing", false);
thread = args.getString("thread");
id = args.getLong("id", -1);
search = args.getString("search");
@ -269,7 +267,7 @@ public class FragmentMessages extends FragmentBase {
int zoom = prefs.getInt("zoom", compact ? 0 : 1);
adapter = new AdapterMessage(
getContext(), getViewLifecycleOwner(),
viewType, outgoing, compact, zoom, iProperties);
viewType, compact, zoom, iProperties);
rvMessage.setAdapter(adapter);
@ -367,8 +365,7 @@ public class FragmentMessages extends FragmentBase {
lbm.sendBroadcast(
new Intent(ActivityView.ACTION_VIEW_MESSAGES)
.putExtra("account", drafts.account)
.putExtra("folder", drafts.id)
.putExtra("outgoing", drafts.isOutgoing()));
.putExtra("folder", drafts.id));
return true;
}

View File

@ -327,7 +327,6 @@ public class Helper {
draft.to = new Address[]{Helper.myAddress()};
draft.subject = context.getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME + " debug info";
draft.received = new Date().getTime();
draft.setContactInfo(context);
draft.id = db.message().insertMessage(draft);
draft.write(context, body);
db.message().setMessageContent(draft.id, true, HtmlHelper.getPreview(body));

View File

@ -2607,8 +2607,11 @@ public class ServiceSynchronize extends LifecycleService {
if (message == null)
return;
if (message.setContactInfo(context))
db.message().updateMessage(message);
if (message.avatar == null && !folder.isOutgoing()) {
message.avatar = EntityMessage.getLookupUri(context, message.from);
if (message.avatar != null)
db.message().updateMessage(message);
}
if (download) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);