diff --git a/src/org/thoughtcrime/securesms/ConversationAdapter.java b/src/org/thoughtcrime/securesms/ConversationAdapter.java index 23d7fa5e34..3befd8afc2 100644 --- a/src/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java @@ -22,12 +22,14 @@ import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; +import org.thoughtcrime.redphone.util.Conversions; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -39,6 +41,8 @@ import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.LRUCache; import java.lang.ref.SoftReference; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.HashSet; import java.util.Locale; @@ -46,6 +50,7 @@ import java.util.Map; import java.util.Set; import org.thoughtcrime.securesms.util.ViewUtil; +import org.thoughtcrime.securesms.util.VisibleForTesting; /** * A cursor adapter for a conversation thread. Ultimately @@ -69,12 +74,13 @@ public class ConversationAdapter private final Set batchSelected = Collections.synchronizedSet(new HashSet()); - private final ItemClickListener clickListener; - private final MasterSecret masterSecret; - private final Locale locale; - private final Recipients recipients; - private final MmsSmsDatabase db; - private final LayoutInflater inflater; + private final @Nullable ItemClickListener clickListener; + private final @NonNull MasterSecret masterSecret; + private final @NonNull Locale locale; + private final @NonNull Recipients recipients; + private final @NonNull MmsSmsDatabase db; + private final @NonNull LayoutInflater inflater; + private final @NonNull MessageDigest digest; protected static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(final @NonNull V itemView) { @@ -92,6 +98,23 @@ public class ConversationAdapter void onItemLongClick(ConversationItem item); } + @SuppressWarnings("ConstantConditions") + @VisibleForTesting + ConversationAdapter(Context context, Cursor cursor) { + super(context, cursor); + try { + this.masterSecret = null; + this.locale = null; + this.clickListener = null; + this.recipients = null; + this.inflater = null; + this.db = null; + this.digest = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException nsae) { + throw new AssertionError("SHA1 isn't supported!"); + } + } + public ConversationAdapter(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull Locale locale, @@ -100,12 +123,19 @@ public class ConversationAdapter @NonNull Recipients recipients) { super(context, cursor); - this.masterSecret = masterSecret; - this.locale = locale; - this.clickListener = clickListener; - this.recipients = recipients; - this.inflater = LayoutInflater.from(context); - this.db = DatabaseFactory.getMmsSmsDatabase(context); + try { + this.masterSecret = masterSecret; + this.locale = locale; + this.clickListener = clickListener; + this.recipients = recipients; + this.inflater = LayoutInflater.from(context); + this.db = DatabaseFactory.getMmsSmsDatabase(context); + this.digest = MessageDigest.getInstance("SHA1"); + + setHasStableIds(true); + } catch (NoSuchAlgorithmException nsae) { + throw new AssertionError("SHA1 isn't supported!"); + } } @Override @@ -114,7 +144,8 @@ public class ConversationAdapter super.changeCursor(cursor); } - @Override public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) { + @Override + public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID)); String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT)); MessageRecord messageRecord = getMessageRecord(id, cursor, type); @@ -122,7 +153,8 @@ public class ConversationAdapter viewHolder.getView().bind(masterSecret, messageRecord, locale, batchSelected, recipients); } - @Override public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { + @Override + public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType)); if (viewType == MESSAGE_TYPE_INCOMING || viewType == MESSAGE_TYPE_OUTGOING) { itemView.setOnClickListener(new OnClickListener() { @@ -143,7 +175,8 @@ public class ConversationAdapter return new ViewHolder(itemView); } - @Override public void onItemViewRecycled(ViewHolder holder) { + @Override + public void onItemViewRecycled(ViewHolder holder) { holder.getView().unbind(); } @@ -171,6 +204,13 @@ public class ConversationAdapter } } + @Override + public long getItemId(@NonNull Cursor cursor) { + final String unique = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsColumns.UNIQUE_ROW_ID)); + final byte[] bytes = digest.digest(unique.getBytes()); + return Conversions.byteArrayToLong(bytes); + } + private MessageRecord getMessageRecord(long messageId, Cursor cursor, String type) { final SoftReference reference = messageRecordCache.get(type + messageId); if (reference != null) { diff --git a/src/org/thoughtcrime/securesms/ConversationListAdapter.java b/src/org/thoughtcrime/securesms/ConversationListAdapter.java index a0a47a328c..98b6394d0a 100644 --- a/src/org/thoughtcrime/securesms/ConversationListAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationListAdapter.java @@ -92,6 +92,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter