Removed loading of each contact's picture causin OutOfMemory exceptions when contact list is large + fixed contacts first/last name

This commit is contained in:
Sylvain Berfini 2017-01-06 17:13:01 +01:00
parent ada6eee4ba
commit 6122078e30
6 changed files with 25 additions and 98 deletions

View file

@ -1110,12 +1110,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
displayName = contact.getFullName(); displayName = contact.getFullName();
} }
if (contact.hasPhoto()) { if (contact.hasPhoto()) {
Bitmap photo = contact.getPhoto(); LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
if (photo != null) {
holder.contactPicture.setImageBitmap(photo);
} else {
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
}
} else { } else {
holder.contactPicture.setImageResource(R.drawable.avatar); holder.contactPicture.setImageResource(R.drawable.avatar);
} }

View file

@ -422,12 +422,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
if (contact != null) { if (contact != null) {
Bitmap photo = contact.getPhoto(); LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
if (photo != null) {
holder.contactPicture.setImageBitmap(photo);
} else {
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
}
} else { } else {
holder.contactPicture.setImageResource(R.drawable.avatar); holder.contactPicture.setImageResource(R.drawable.avatar);
} }

View file

@ -524,12 +524,7 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
} }
if (contact.hasPhoto()) { if (contact.hasPhoto()) {
Bitmap photo = contact.getPhoto(); LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
if (photo != null) {
holder.contactPicture.setImageBitmap(photo);
} else {
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri());
}
} else { } else {
holder.contactPicture.setImageResource(R.drawable.avatar); holder.contactPicture.setImageResource(R.drawable.avatar);
} }

View file

@ -300,10 +300,7 @@ public class ContactsManager extends ContentObserver {
while (c.moveToNext()) { while (c.moveToNext()) {
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID)); String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
String displayName = c.getString(c.getColumnIndex(Data.DISPLAY_NAME)); String displayName = c.getString(c.getColumnIndex(Data.DISPLAY_NAME));
String givenName = c.getString(c.getColumnIndex(CommonDataKinds.StructuredName.GIVEN_NAME));
String familyName = c.getString(c.getColumnIndex(CommonDataKinds.StructuredName.FAMILY_NAME));
LinphoneContact contact = new LinphoneContact(); LinphoneContact contact = new LinphoneContact();
contact.setFirstNameAndLastName(givenName, familyName);
contact.setFullName(displayName); contact.setFullName(displayName);
contact.setAndroidId(id); contact.setAndroidId(id);
contacts.add(contact); contacts.add(contact);
@ -359,7 +356,7 @@ public class ContactsManager extends ContentObserver {
TimeUnit.MILLISECONDS.toMinutes(timeElapsed), TimeUnit.MILLISECONDS.toMinutes(timeElapsed),
TimeUnit.MILLISECONDS.toSeconds(timeElapsed) - TimeUnit.MILLISECONDS.toSeconds(timeElapsed) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed))); TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)));
Log.d("[ContactsManager] minimal informations for " + contacts.size() + " contacts gathered in " + time); Log.i("[ContactsManager] minimal informations for " + contacts.size() + " contacts gathered in " + time);
// Public the current list of contacts without all the informations populated // Public the current list of contacts without all the informations populated
publishProgress(contacts); publishProgress(contacts);
@ -372,7 +369,7 @@ public class ContactsManager extends ContentObserver {
TimeUnit.MILLISECONDS.toMinutes(timeElapsed), TimeUnit.MILLISECONDS.toMinutes(timeElapsed),
TimeUnit.MILLISECONDS.toSeconds(timeElapsed) - TimeUnit.MILLISECONDS.toSeconds(timeElapsed) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed))); TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeElapsed)));
Log.d("[ContactsManager] complete informations for " + contacts.size() + " contacts gathered in " + time); Log.i("[ContactsManager] complete informations for " + contacts.size() + " contacts gathered in " + time);
return contacts; return contacts;
} }
@ -452,7 +449,7 @@ public class ContactsManager extends ContentObserver {
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL " + "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))"; + "' AND " + CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))";
String[] projection = new String[] { Data.CONTACT_ID, Data.DISPLAY_NAME, CommonDataKinds.StructuredName.GIVEN_NAME, CommonDataKinds.StructuredName.FAMILY_NAME }; String[] projection = new String[] { Data.CONTACT_ID, Data.DISPLAY_NAME };
String query = Data.DISPLAY_NAME + " IS NOT NULL AND (" + req + ")"; String query = Data.DISPLAY_NAME + " IS NOT NULL AND (" + req + ")";
Cursor cursor = cr.query(Data.CONTENT_URI, projection, query, null, " lower(" + Data.DISPLAY_NAME + ") COLLATE UNICODE ASC"); Cursor cursor = cr.query(Data.CONTENT_URI, projection, query, null, " lower(" + Data.DISPLAY_NAME + ") COLLATE UNICODE ASC");
@ -470,14 +467,9 @@ public class ContactsManager extends ContentObserver {
int contactID = cursor.getColumnIndex(Data.CONTACT_ID); int contactID = cursor.getColumnIndex(Data.CONTACT_ID);
int displayName = cursor.getColumnIndex(Data.DISPLAY_NAME); int displayName = cursor.getColumnIndex(Data.DISPLAY_NAME);
int givenName = cursor.getColumnIndex(CommonDataKinds.StructuredName.GIVEN_NAME);
int familyName = cursor.getColumnIndex(CommonDataKinds.StructuredName.FAMILY_NAME);
newRow[contactID] = cursor.getString(contactID); newRow[contactID] = cursor.getString(contactID);
newRow[displayName] = cursor.getString(displayName); newRow[displayName] = cursor.getString(displayName);
newRow[givenName] = cursor.getString(givenName);
newRow[familyName] = cursor.getString(familyName);
result.addRow(newRow); result.addRow(newRow);
} }
} }

View file

@ -473,16 +473,7 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On
final String sipUri = address.asString(); final String sipUri = address.asString();
if (c != null) { if (c != null) {
displayName = c.getFullName(); displayName = c.getFullName();
if (c.hasPhoto()) { LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, c.getPhotoUri(), c.getThumbnailUri());
Bitmap photo = c.getPhoto();
if (photo != null) {
holder.contactPicture.setImageBitmap(photo);
} else {
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, c.getPhotoUri(), c.getThumbnailUri());
}
} else {
LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, c.getPhotoUri(), c.getThumbnailUri());
}
} else { } else {
holder.contactPicture.setImageResource(R.drawable.avatar); holder.contactPicture.setImageResource(R.drawable.avatar);
} }

View file

@ -18,8 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
package org.linphone; package org.linphone;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -29,7 +27,6 @@ import java.util.Locale;
import org.linphone.core.LinphoneAddress; import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneFriend.SubscribePolicy; import org.linphone.core.LinphoneFriend.SubscribePolicy;
import org.linphone.core.PresenceBasicStatus; import org.linphone.core.PresenceBasicStatus;
@ -41,10 +38,8 @@ import android.content.ContentResolver;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.CommonDataKinds;
public class LinphoneContact implements Serializable, Comparable<LinphoneContact> { public class LinphoneContact implements Serializable, Comparable<LinphoneContact> {
@ -60,7 +55,6 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
private transient ArrayList<ContentProviderOperation> changesToCommit; private transient ArrayList<ContentProviderOperation> changesToCommit;
private transient ArrayList<ContentProviderOperation> changesToCommit2; private transient ArrayList<ContentProviderOperation> changesToCommit2;
private boolean hasSipAddress; private boolean hasSipAddress;
private transient Bitmap photoBitmap, thumbnailBitmap;
public LinphoneContact() { public LinphoneContact() {
addresses = new ArrayList<LinphoneNumberOrAddress>(); addresses = new ArrayList<LinphoneNumberOrAddress>();
@ -72,19 +66,6 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
hasSipAddress = false; hasSipAddress = false;
} }
@Override
protected void finalize() throws Throwable {
if (photoBitmap != null) {
photoBitmap.recycle();
photoBitmap = null;
}
if (thumbnailBitmap != null) {
thumbnailBitmap.recycle();
thumbnailBitmap = null;
}
super.finalize();
}
@Override @Override
public int compareTo(LinphoneContact contact) { public int compareTo(LinphoneContact contact) {
String fullName = getFullName() != null ? getFullName().toUpperCase(Locale.getDefault()) : ""; String fullName = getFullName() != null ? getFullName().toUpperCase(Locale.getDefault()) : "";
@ -188,60 +169,21 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
public void setPhotoUri(Uri uri) { public void setPhotoUri(Uri uri) {
if (uri.equals(photoUri)) return; if (uri.equals(photoUri)) return;
photoUri = uri; photoUri = uri;
if (photoBitmap != null) {
photoBitmap.recycle();
}
try {
photoBitmap = MediaStore.Images.Media.getBitmap(ContactsManager.getInstance().getContentResolver(), photoUri);
} catch (FileNotFoundException e) {
// Let's not say anything if the picture doesn't exist, it will pollute the logs
} catch (IOException e) {
Log.e(e);
}
} }
public Uri getPhotoUri() { public Uri getPhotoUri() {
return photoUri; return photoUri;
} }
public Bitmap getPhotoBitmap() {
return photoBitmap;
}
public void setThumbnailUri(Uri uri) { public void setThumbnailUri(Uri uri) {
if (uri.equals(thumbnailUri)) return; if (uri.equals(thumbnailUri)) return;
thumbnailUri = uri; thumbnailUri = uri;
if (thumbnailBitmap != null) {
thumbnailBitmap.recycle();
}
try {
thumbnailBitmap = MediaStore.Images.Media.getBitmap(ContactsManager.getInstance().getContentResolver(), thumbnailUri);
} catch (FileNotFoundException e) {
// Let's not say anything if the picture doesn't exist, it will pollute the logs
} catch (IOException e) {
Log.e(e);
}
} }
public Uri getThumbnailUri() { public Uri getThumbnailUri() {
return thumbnailUri; return thumbnailUri;
} }
public Bitmap getThumbnailBitmap() {
return thumbnailBitmap;
}
public Bitmap getPhoto() {
if (photoBitmap != null) {
return photoBitmap;
} else if (thumbnailBitmap != null) {
return thumbnailBitmap;
}
return null;
}
public void setPhoto(byte[] photo) { public void setPhoto(byte[] photo) {
if (photo != null) { if (photo != null) {
if (isAndroidContact()) { if (isAndroidContact()) {
@ -560,6 +502,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
hasSipAddress = false; hasSipAddress = false;
if (isAndroidContact()) { if (isAndroidContact()) {
getContactNames();
getNativeContactOrganization(); getNativeContactOrganization();
setThumbnailUri(getContactThumbnailPictureUri()); setThumbnailUri(getContactThumbnailPictureUri());
setPhotoUri(getContactPictureUri()); setPhotoUri(getContactPictureUri());
@ -654,6 +597,22 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.DISPLAY_PHOTO); return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
} }
private void getContactNames() {
ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
String[] proj = new String[]{ ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, ContactsContract.Contacts.DISPLAY_NAME };
String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?";
String[] args = new String[]{ getAndroidId(), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
Cursor c = resolver.query(ContactsContract.Data.CONTENT_URI, proj, select, args, null);
if (c != null) {
if (c.moveToFirst()) {
firstName = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
lastName = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
fullName = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
}
c.close();
}
}
private void getNativeContactOrganization() { private void getNativeContactOrganization() {
ContentResolver resolver = ContactsManager.getInstance().getContentResolver(); ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
String[] proj = new String[]{ ContactsContract.CommonDataKinds.Organization.COMPANY }; String[] proj = new String[]{ ContactsContract.CommonDataKinds.Organization.COMPANY };