From 7c5fa67f43ecc36f36347f6c9e6a160d38cd3d28 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 8 Aug 2016 14:12:16 +0200 Subject: [PATCH] Improve scrolling speed in lists --- src/org/linphone/ChatFragment.java | 24 +++-- src/org/linphone/ChatListFragment.java | 109 ++++++++++++--------- src/org/linphone/ContactsListFragment.java | 89 ++++++++++------- src/org/linphone/HistoryListFragment.java | 53 ++++++---- src/org/linphone/LinphoneContact.java | 59 +++++++++++ src/org/linphone/LinphoneManager.java | 12 --- 6 files changed, 229 insertions(+), 117 deletions(-) diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index 42e404914..2f6ccb60e 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -387,7 +387,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC CheckBox deleteChatBubble = (CheckBox) v.findViewById(R.id.delete_message); - if(isEditMode) { + if (isEditMode) { deleteChatBubble.setVisibility(View.VISIBLE); if (message.isOutgoing()) { RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); @@ -1043,6 +1043,16 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC } class SearchContactsListAdapter extends BaseAdapter { + private class ViewHolder { + public TextView name; + public TextView address; + + public ViewHolder(View view) { + name = (TextView) view.findViewById(R.id.contact_name); + address = (TextView) view.findViewById(R.id.contact_address); + } + } + private List contacts; private LayoutInflater mInflater; @@ -1093,24 +1103,26 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC public View getView(int position, View convertView, ViewGroup parent) { View view = null; ContactAddress contact; + ViewHolder holder = null; + do { contact = getItem(position); } while (contact == null); if (convertView != null) { view = convertView; + holder = (ViewHolder) view.getTag(); } else { view = mInflater.inflate(R.layout.search_contact_cell, parent, false); + holder = new ViewHolder(view); + view.setTag(holder); } final String a = contact.address; LinphoneContact c = contact.contact; - TextView name = (TextView) view.findViewById(R.id.contact_name); - name.setText(c.getFullName()); - - TextView address = (TextView) view.findViewById(R.id.contact_address); - address.setText(a); + holder.name.setText(c.getFullName()); + holder.address.setText(a); view.setOnClickListener(new OnClickListener() { @Override diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java index d978f2ad8..d18c84fdb 100644 --- a/src/org/linphone/ChatListFragment.java +++ b/src/org/linphone/ChatListFragment.java @@ -30,6 +30,7 @@ import org.linphone.mediastream.Log; import android.app.Dialog; import android.app.Fragment; +import android.graphics.Bitmap; import android.graphics.Typeface; import android.os.Bundle; import android.view.ContextMenu; @@ -117,15 +118,16 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte } } - private void removeChatsConversation(){ + private void removeChatsConversation() { int size = chatList.getAdapter().getCount(); - for(int i=0; i adapter, View view, int position, long id) { - String sipUri = (String) view.getTag(); + String sipUri = chatList.getAdapter().getItem(position).toString(); if (LinphoneActivity.isInstanciated() && !isEditMode) { LinphoneActivity.instance().displayChat(sipUri); @@ -339,7 +341,24 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte } class ChatListAdapter extends BaseAdapter { - + private class ViewHolder { + public TextView lastMessageView; + public TextView date; + public TextView displayName; + public TextView unreadMessages; + public CheckBox select; + public ImageView contactPicture; + + public ViewHolder(View view) { + lastMessageView = (TextView) view.findViewById(R.id.lastMessage); + date = (TextView) view.findViewById(R.id.date); + displayName = (TextView) view.findViewById(R.id.sipUri); + unreadMessages = (TextView) view.findViewById(R.id.unreadMessages); + select = (CheckBox) view.findViewById(R.id.delete_chatroom); + contactPicture = (ImageView) view.findViewById(R.id.contact_picture); + } + } + ChatListAdapter() {} public int getCount() { @@ -347,7 +366,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte } public Object getItem(int position) { - return position; + return mConversations.get(position); } public long getItemId(int position) { @@ -356,21 +375,23 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte public View getView(final int position, View convertView, ViewGroup parent) { View view = null; + ViewHolder holder = null; + String sipUri = mConversations.get(position); if (convertView != null) { view = convertView; + holder = (ViewHolder) view.getTag(); } else { view = mInflater.inflate(R.layout.chatlist_cell, parent, false); + holder = new ViewHolder(view); + view.setTag(holder); } - - String sipUri = mConversations.get(position); - view.setTag(sipUri); LinphoneAddress address; try { address = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri); } catch (LinphoneCoreException e) { - Log.e("Chat view cannot parse address",e); + Log.e("Chat view cannot parse address", e); return view; } @@ -378,57 +399,55 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte String message = ""; Long time; - TextView lastMessageView = (TextView) view.findViewById(R.id.lastMessage); - TextView date = (TextView) view.findViewById(R.id.date); - TextView displayName = (TextView) view.findViewById(R.id.sipUri); - TextView unreadMessages = (TextView) view.findViewById(R.id.unreadMessages); - CheckBox select = (CheckBox) view.findViewById(R.id.delete_chatroom); - ImageView contactPicture = (ImageView) view.findViewById(R.id.contact_picture); - LinphoneChatRoom chatRoom = LinphoneManager.getLc().getChatRoom(address); int unreadMessagesCount = chatRoom.getUnreadMessagesCount(); LinphoneChatMessage[] history = chatRoom.getHistory(1); LinphoneChatMessage msg = history[0]; if(msg.getFileTransferInformation() != null || msg.getExternalBodyUrl() != null || msg.getAppData() != null ){ - lastMessageView.setBackgroundResource(R.drawable.chat_file_message); + holder.lastMessageView.setBackgroundResource(R.drawable.chat_file_message); time = msg.getTime(); - date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format))); - lastMessageView.setText(""); + holder.date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format))); + holder.lastMessageView.setText(""); } else if (msg.getText() != null && msg.getText().length() > 0 ){ message = msg.getText(); - lastMessageView.setBackgroundResource(0); + holder.lastMessageView.setBackgroundResource(0); time = msg.getTime(); - date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format))); - lastMessageView.setText(message); + holder.date.setText(LinphoneUtils.timestampToHumanDate(getActivity(),time,getString(R.string.messages_list_date_format))); + holder.lastMessageView.setText(message); } - displayName.setSelected(true); // For animation - displayName.setText(contact == null ? LinphoneUtils.getAddressDisplayName(address) : contact.getFullName()); + holder.displayName.setSelected(true); // For animation + holder.displayName.setText(contact == null ? LinphoneUtils.getAddressDisplayName(address) : contact.getFullName()); if (contact != null) { - LinphoneUtils.setImagePictureFromUri(view.getContext(), contactPicture, contact.getPhotoUri(), contact.getThumbnailUri()); + Bitmap photo = contact.getPhoto(); + if (photo != null) { + holder.contactPicture.setImageBitmap(photo); + } else { + LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri()); + } } else { - contactPicture.setImageResource(R.drawable.avatar); + holder.contactPicture.setImageResource(R.drawable.avatar); } if (unreadMessagesCount > 0) { - unreadMessages.setVisibility(View.VISIBLE); - unreadMessages.setText(String.valueOf(unreadMessagesCount)); - if(unreadMessagesCount > 99){ - unreadMessages.setTextSize(12); + holder.unreadMessages.setVisibility(View.VISIBLE); + holder.unreadMessages.setText(String.valueOf(unreadMessagesCount)); + if (unreadMessagesCount > 99) { + holder.unreadMessages.setTextSize(12); } - displayName.setTypeface(null, Typeface.BOLD); + holder.displayName.setTypeface(null, Typeface.BOLD); } else { - unreadMessages.setVisibility(View.GONE); - displayName.setTypeface(null, Typeface.NORMAL); + holder.unreadMessages.setVisibility(View.GONE); + holder.displayName.setTypeface(null, Typeface.NORMAL); } if (isEditMode) { - unreadMessages.setVisibility(View.GONE); - select.setVisibility(View.VISIBLE); - select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + holder.unreadMessages.setVisibility(View.GONE); + holder.select.setVisibility(View.VISIBLE); + holder.select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { chatList.setItemChecked(position, b); @@ -450,13 +469,13 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte } }); if(chatList.isItemChecked(position)) { - select.setChecked(true); + holder.select.setChecked(true); } else { - select.setChecked(false); + holder.select.setChecked(false); } } else { if (unreadMessagesCount > 0) { - unreadMessages.setVisibility(View.VISIBLE); + holder.unreadMessages.setVisibility(View.VISIBLE); } } return view; diff --git a/src/org/linphone/ContactsListFragment.java b/src/org/linphone/ContactsListFragment.java index de822fabe..4e75ce1d6 100644 --- a/src/org/linphone/ContactsListFragment.java +++ b/src/org/linphone/ContactsListFragment.java @@ -30,6 +30,7 @@ import org.linphone.core.PresenceActivityType; import android.app.Dialog; import android.app.Fragment; +import android.graphics.Bitmap; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; @@ -416,6 +417,28 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O } class ContactsListAdapter extends BaseAdapter implements SectionIndexer { + private class ViewHolder { + public CheckBox delete; + public ImageView linphoneFriend; + public TextView name; + public LinearLayout separator; + public TextView separatorText; + public ImageView contactPicture; + public TextView organization; + public ImageView friendStatus; + + public ViewHolder(View view) { + delete = (CheckBox) view.findViewById(R.id.delete); + linphoneFriend = (ImageView) view.findViewById(R.id.friendLinphone); + name = (TextView) view.findViewById(R.id.name); + separator = (LinearLayout) view.findViewById(R.id.separator); + separatorText = (TextView) view.findViewById(R.id.separator_text); + contactPicture = (ImageView) view.findViewById(R.id.contact_picture); + organization = (TextView) view.findViewById(R.id.contactOrganization); + friendStatus = (ImageView) view.findViewById(R.id.friendStatus); + } + } + private List contacts; String[] sections; ArrayList sectionsList; @@ -461,58 +484,57 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O LinphoneContact contact = (LinphoneContact) getItem(position); if (contact == null) return null; + ViewHolder holder = null; if (convertView != null) { view = convertView; + holder = (ViewHolder) view.getTag(); } else { view = mInflater.inflate(R.layout.contact_cell, parent, false); + holder = new ViewHolder(view); + view.setTag(holder); } - - CheckBox delete = (CheckBox) view.findViewById(R.id.delete); - ImageView linphoneFriend = (ImageView) view.findViewById(R.id.friendLinphone); - TextView name = (TextView) view.findViewById(R.id.name); - name.setText(contact.getFullName()); - - LinearLayout separator = (LinearLayout) view.findViewById(R.id.separator); - TextView separatorText = (TextView) view.findViewById(R.id.separator_text); + holder.name.setText(contact.getFullName()); + if (getPositionForSection(getSectionForPosition(position)) != position) { - separator.setVisibility(View.GONE); + holder.separator.setVisibility(View.GONE); } else { - separator.setVisibility(View.VISIBLE); + holder.separator.setVisibility(View.VISIBLE); String fullName = contact.getFullName(); if (fullName != null && !fullName.isEmpty()) { - separatorText.setText(String.valueOf(fullName.charAt(0))); + holder.separatorText.setText(String.valueOf(fullName.charAt(0))); } } if (contact.isInLinphoneFriendList()) { - linphoneFriend.setVisibility(View.VISIBLE); + holder.linphoneFriend.setVisibility(View.VISIBLE); } else { - linphoneFriend.setVisibility(View.GONE); + holder.linphoneFriend.setVisibility(View.GONE); } - ImageView icon = (ImageView) view.findViewById(R.id.contact_picture); if (contact.hasPhoto()) { - LinphoneUtils.setImagePictureFromUri(getActivity(), icon, contact.getPhotoUri(), contact.getThumbnailUri()); - } else if (contact.getPhotoUri() != null) { - icon.setImageURI(contact.getPhotoUri()); + Bitmap photo = contact.getPhoto(); + if (photo != null) { + holder.contactPicture.setImageBitmap(photo); + } else { + LinphoneUtils.setImagePictureFromUri(getActivity(), holder.contactPicture, contact.getPhotoUri(), contact.getThumbnailUri()); + } } else { - icon.setImageResource(R.drawable.avatar); + holder.contactPicture.setImageResource(R.drawable.avatar); } - TextView organization = (TextView) view.findViewById(R.id.contactOrganization); boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization); String org = contact.getOrganization(); if (org != null && !org.isEmpty() && isOrgVisible) { - organization.setText(org); - organization.setVisibility(View.VISIBLE); + holder.organization.setText(org); + holder.organization.setVisibility(View.VISIBLE); } else { - organization.setVisibility(View.GONE); + holder.organization.setVisibility(View.GONE); } if (isEditMode) { - delete.setVisibility(View.VISIBLE); - delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + holder.delete.setVisibility(View.VISIBLE); + holder.delete.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { contactsList.setItemChecked(position, b); @@ -534,29 +556,28 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O } }); if (contactsList.isItemChecked(position)) { - delete.setChecked(true); + holder.delete.setChecked(true); } else { - delete.setChecked(false); + holder.delete.setChecked(false); } } else { - delete.setVisibility(View.GONE); + holder.delete.setVisibility(View.GONE); } - ImageView friendStatus = (ImageView) view.findViewById(R.id.friendStatus); LinphoneFriend[] friends = LinphoneManager.getLc().getFriendList(); if (!ContactsManager.getInstance().isContactPresenceDisabled() && friends != null) { - friendStatus.setVisibility(View.VISIBLE); + holder.friendStatus.setVisibility(View.VISIBLE); PresenceActivityType presenceActivity = friends[0].getPresenceModel().getActivity().getType(); if (presenceActivity == PresenceActivityType.Online) { - friendStatus.setImageResource(R.drawable.led_connected); + holder.friendStatus.setImageResource(R.drawable.led_connected); } else if (presenceActivity == PresenceActivityType.Busy) { - friendStatus.setImageResource(R.drawable.led_error); + holder.friendStatus.setImageResource(R.drawable.led_error); } else if (presenceActivity == PresenceActivityType.Away) { - friendStatus.setImageResource(R.drawable.led_inprogress); + holder.friendStatus.setImageResource(R.drawable.led_inprogress); } else if (presenceActivity == PresenceActivityType.Offline) { - friendStatus.setImageResource(R.drawable.led_disconnected); + holder.friendStatus.setImageResource(R.drawable.led_disconnected); } else { - friendStatus.setImageResource(R.drawable.call_quality_indicator_0); + holder.friendStatus.setImageResource(R.drawable.call_quality_indicator_0); } } diff --git a/src/org/linphone/HistoryListFragment.java b/src/org/linphone/HistoryListFragment.java index bb148278c..83840f0da 100644 --- a/src/org/linphone/HistoryListFragment.java +++ b/src/org/linphone/HistoryListFragment.java @@ -31,6 +31,7 @@ import org.linphone.core.LinphoneCallLog.CallStatus; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; +import android.graphics.Bitmap; import android.os.Bundle; import android.app.Fragment; import android.view.LayoutInflater; @@ -349,6 +350,22 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On } class CallHistoryAdapter extends BaseAdapter { + private class ViewHolder { + public TextView contact; + public ImageView detail; + public CheckBox select; + public ImageView callDirection; + public ImageView contactPicture; + + public ViewHolder(View view) { + contact = (TextView) view.findViewById(R.id.sip_uri); + detail = (ImageView) view.findViewById(R.id.detail); + select = (CheckBox) view.findViewById(R.id.delete); + callDirection = (ImageView) view.findViewById(R.id.icon); + contactPicture = (ImageView) view.findViewById(R.id.contact_picture); + } + } + CallHistoryAdapter(Context aContext) { } @@ -401,23 +418,20 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On public View getView(final int position, View convertView, ViewGroup parent) { View view = null; - ViewHolder holder; + ViewHolder holder = null; + if (convertView != null) { view = convertView; holder = (ViewHolder) view.getTag(); } else { view = mInflater.inflate(R.layout.history_cell, parent,false); - holder = new ViewHolder(); - holder.contact = (TextView) view.findViewById(R.id.sip_uri); - holder.detail = (ImageView) view.findViewById(R.id.detail); - holder.select = (CheckBox) view.findViewById(R.id.delete); - holder.callDirection = (ImageView) view.findViewById(R.id.icon); - holder.contactPicture = (ImageView) view.findViewById(R.id.contact_picture); + holder = new ViewHolder(view); + view.setTag(holder); } final LinphoneCallLog log = mLogs.get(position); long timestamp = log.getTimestamp(); - final LinphoneAddress address; + LinphoneAddress address; holder.contact.setSelected(true); // For automated horizontal scrolling of long texts @@ -457,9 +471,18 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address); String displayName = null; final String sipUri = address.asString(); - if(c != null){ + if (c != null) { displayName = c.getFullName(); - LinphoneUtils.setImagePictureFromUri(view.getContext(),holder.contactPicture,c.getPhotoUri(),c.getThumbnailUri()); + if (c.hasPhoto()) { + 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 { holder.contactPicture.setImageResource(R.drawable.avatar); } @@ -469,7 +492,6 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On } else { holder.contact.setText(displayName); } - //view.setTag(sipUri); if (isEditMode) { holder.select.setVisibility(View.VISIBLE); @@ -512,16 +534,7 @@ public class HistoryListFragment extends Fragment implements OnClickListener, On } }); } - view.setTag(holder); return view; } } - - static class ViewHolder { - TextView contact; - ImageView detail; - CheckBox select; - ImageView callDirection; - ImageView contactPicture; - } } \ No newline at end of file diff --git a/src/org/linphone/LinphoneContact.java b/src/org/linphone/LinphoneContact.java index 6d7670f22..c0b6419fa 100644 --- a/src/org/linphone/LinphoneContact.java +++ b/src/org/linphone/LinphoneContact.java @@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.linphone; +import java.io.FileNotFoundException; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; @@ -38,8 +40,10 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; +import android.graphics.Bitmap; import android.net.Uri; import android.provider.ContactsContract; +import android.provider.MediaStore; import android.provider.ContactsContract.CommonDataKinds; public class LinphoneContact implements Serializable, Comparable { @@ -55,6 +59,7 @@ public class LinphoneContact implements Serializable, Comparable changesToCommit; private transient ArrayList changesToCommit2; private boolean hasSipAddress; + private Bitmap photoBitmap, thumbnailBitmap; public LinphoneContact() { addresses = new ArrayList(); @@ -66,6 +71,19 @@ public class LinphoneContact implements Serializable, Comparable