Refactor recipient access.
1) Refactor recipient class to support asynchronous loading operations. 2) Refactor recipient factory to simplify recipient access. 3) Consoliate everything into one recipient provider that is capable of doing async lookups and intelligent caching.pull/1/head
parent
f685cb550b
commit
9939830551
@ -0,0 +1,69 @@
|
||||
package org.thoughtcrime.securesms.recipients;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ContactPhotoFactory {
|
||||
|
||||
private static final Object defaultPhotoLock = new Object();
|
||||
private static final Object localUserLock = new Object();
|
||||
|
||||
private static Bitmap defaultContactPhoto;
|
||||
private static Bitmap localUserContactPhoto;
|
||||
|
||||
private static final String[] CONTENT_URI_PROJECTION = new String[] {
|
||||
ContactsContract.Contacts._ID,
|
||||
ContactsContract.Contacts.DISPLAY_NAME,
|
||||
ContactsContract.Contacts.LOOKUP_KEY
|
||||
};
|
||||
|
||||
public static Bitmap getDefaultContactPhoto(Context context) {
|
||||
synchronized (defaultPhotoLock) {
|
||||
if (defaultContactPhoto == null)
|
||||
defaultContactPhoto = BitmapFactory.decodeResource(context.getResources(),
|
||||
R.drawable.ic_contact_picture);
|
||||
}
|
||||
|
||||
return defaultContactPhoto;
|
||||
}
|
||||
|
||||
public static Bitmap getLocalUserContactPhoto(Context context, Uri uri) {
|
||||
synchronized (localUserLock) {
|
||||
if (localUserContactPhoto == null) {
|
||||
Cursor cursor = context.getContentResolver().query(uri, CONTENT_URI_PROJECTION,
|
||||
null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
localUserContactPhoto = getContactPhoto(context, Uri.withAppendedPath(Contacts.CONTENT_URI,
|
||||
cursor.getLong(0) + ""));
|
||||
} else {
|
||||
localUserContactPhoto = getDefaultContactPhoto(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return localUserContactPhoto;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
synchronized (localUserLock) {
|
||||
localUserContactPhoto = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap getContactPhoto(Context context, Uri uri) {
|
||||
InputStream inputStream = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
|
||||
|
||||
if (inputStream == null) return ContactPhotoFactory.getDefaultContactPhoto(context);
|
||||
else return BitmapFactory.decodeStream(inputStream);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
public interface FutureTaskListener<V> {
|
||||
public void onSuccess(V result);
|
||||
public void onFailure(Throwable error);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LRUCache<K,V> extends LinkedHashMap<K,V> {
|
||||
|
||||
private final int maxSize;
|
||||
|
||||
public LRUCache(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry (Map.Entry<K,V> eldest) {
|
||||
return size() > maxSize;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
public class ListenableFutureTask<V> extends FutureTask<V> {
|
||||
|
||||
private FutureTaskListener<V> listener;
|
||||
|
||||
public ListenableFutureTask(Callable<V> callable, FutureTaskListener<V> listener) {
|
||||
super(callable);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public synchronized void setListener(FutureTaskListener<V> listener) {
|
||||
this.listener = listener;
|
||||
if (this.isDone()) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void done() {
|
||||
callback();
|
||||
}
|
||||
|
||||
private void callback() {
|
||||
if (this.listener != null) {
|
||||
try {
|
||||
this.listener.onSuccess(get());
|
||||
} catch (ExecutionException ee) {
|
||||
this.listener.onFailure(ee);
|
||||
} catch (InterruptedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue