diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 365a4b29c..67218f62d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -243,12 +243,6 @@ android:theme="@style/TextSecure.LightTheme.Popup" android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" /> - - . - */ -package org.thoughtcrime.securesms; - -import android.annotation.SuppressLint; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.database.Cursor; -import android.graphics.drawable.ColorDrawable; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.loader.app.LoaderManager.LoaderCallbacks; -import androidx.loader.content.Loader; - -import org.thoughtcrime.securesms.conversation.ConversationItem; -import org.thoughtcrime.securesms.database.GroupDatabase; -import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.logging.Log; - -import android.os.Parcelable; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; -import android.widget.TextView; - -import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus; -import org.thoughtcrime.securesms.color.MaterialColor; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.database.GroupReceiptDatabase; -import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo; -import org.thoughtcrime.securesms.database.MmsDatabase; -import org.thoughtcrime.securesms.database.MmsSmsDatabase; -import org.thoughtcrime.securesms.database.SmsDatabase; -import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader; -import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.mms.GlideApp; -import org.thoughtcrime.securesms.mms.GlideRequests; -import org.thoughtcrime.securesms.recipients.LiveRecipient; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.util.DateUtils; -import org.thoughtcrime.securesms.util.DynamicDarkActionBarTheme; -import org.thoughtcrime.securesms.util.DynamicLanguage; -import org.thoughtcrime.securesms.util.DynamicTheme; -import org.thoughtcrime.securesms.util.ExpirationUtil; -import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; -import org.whispersystems.libsignal.util.guava.Optional; - -import java.lang.ref.WeakReference; -import java.sql.Date; -import java.text.SimpleDateFormat; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - -/** - * @author Jake McGinty - */ -public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks { - private final static String TAG = MessageDetailsActivity.class.getSimpleName(); - - public static final String MESSAGE_ID_EXTRA = "message_id"; - public static final String THREAD_ID_EXTRA = "thread_id"; - public static final String IS_PUSH_GROUP_EXTRA = "is_push_group"; - public static final String TYPE_EXTRA = "type"; - public static final String RECIPIENT_EXTRA = "recipient_id"; - - private GlideRequests glideRequests; - private long threadId; - private boolean isPushGroup; - private ConversationItem conversationItem; - private ViewGroup itemParent; - private View metadataContainer; - private View expiresContainer; - private TextView errorText; - private View resendButton; - private TextView sentDate; - private TextView receivedDate; - private TextView expiresInText; - private View receivedContainer; - private TextView transport; - private TextView toFrom; - private ListView recipientsList; - private LayoutInflater inflater; - - private DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme(); - private DynamicLanguage dynamicLanguage = new DynamicLanguage(); - - private boolean running; - - @Override - protected void onPreCreate() { - dynamicTheme.onCreate(this); - dynamicLanguage.onCreate(this); - } - - @Override - public void onCreate(Bundle bundle, boolean ready) { - setContentView(R.layout.message_details_activity); - running = true; - - initializeResources(); - initializeActionBar(); - getSupportLoaderManager().initLoader(0, null, this); - } - - @Override - protected void onResume() { - super.onResume(); - dynamicTheme.onResume(this); - dynamicLanguage.onResume(this); - - assert getSupportActionBar() != null; - getSupportActionBar().setTitle(R.string.AndroidManifest__message_details); - - ApplicationDependencies.getMessageNotifier().setVisibleThread(threadId); - } - - @Override - protected void onPause() { - super.onPause(); - ApplicationDependencies.getMessageNotifier().clearVisibleThread(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - running = false; - } - - private void initializeActionBar() { - assert getSupportActionBar() != null; - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA)); - recipient.observe(this, r -> setActionBarColor(r.getColor())); - - setActionBarColor(recipient.get().getColor()); - } - - private void setActionBarColor(MaterialColor color) { - assert getSupportActionBar() != null; - getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.toActionBarColor(this))); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - getWindow().setStatusBarColor(color.toStatusBarColor(this)); - } - } - - private void initializeResources() { - inflater = LayoutInflater.from(this); - View header = inflater.inflate(R.layout.message_details_header, recipientsList, false); - - threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); - isPushGroup = getIntent().getBooleanExtra(IS_PUSH_GROUP_EXTRA, false); - glideRequests = GlideApp.with(this); - itemParent = header.findViewById(R.id.item_container); - recipientsList = findViewById(R.id.recipients_list); - metadataContainer = header.findViewById(R.id.metadata_container); - errorText = header.findViewById(R.id.error_text); - resendButton = header.findViewById(R.id.resend_button); - sentDate = header.findViewById(R.id.sent_time); - receivedContainer = header.findViewById(R.id.received_container); - receivedDate = header.findViewById(R.id.received_time); - transport = header.findViewById(R.id.transport); - toFrom = header.findViewById(R.id.tofrom); - expiresContainer = header.findViewById(R.id.expires_container); - expiresInText = header.findViewById(R.id.expires_in); - recipientsList.setHeaderDividersEnabled(false); - recipientsList.addHeaderView(header, null, false); - } - - private void updateTransport(MessageRecord messageRecord) { - final String transportText; - if (messageRecord.isOutgoing() && messageRecord.isFailed()) { - transportText = "-"; - } else if (messageRecord.isPending()) { - transportText = getString(R.string.ConversationFragment_pending); - } else if (messageRecord.isPush()) { - transportText = getString(R.string.ConversationFragment_push); - } else if (messageRecord.isMms()) { - transportText = getString(R.string.ConversationFragment_mms); - } else { - transportText = getString(R.string.ConversationFragment_sms); - } - - transport.setText(transportText); - } - - private void updateTime(MessageRecord messageRecord) { - sentDate.setOnLongClickListener(null); - receivedDate.setOnLongClickListener(null); - - if (messageRecord.isPending() || messageRecord.isFailed()) { - sentDate.setText("-"); - receivedContainer.setVisibility(View.GONE); - } else { - Locale dateLocale = dynamicLanguage.getCurrentLocale(); - SimpleDateFormat dateFormatter = DateUtils.getDetailedDateFormatter(this, dateLocale); - sentDate.setText(dateFormatter.format(new Date(messageRecord.getDateSent()))); - sentDate.setOnLongClickListener(v -> { - copyToClipboard(String.valueOf(messageRecord.getDateSent())); - return true; - }); - - if (messageRecord.getDateReceived() != messageRecord.getDateSent() && !messageRecord.isOutgoing()) { - receivedDate.setText(dateFormatter.format(new Date(messageRecord.getDateReceived()))); - receivedDate.setOnLongClickListener(v -> { - copyToClipboard(String.valueOf(messageRecord.getDateReceived())); - return true; - }); - receivedContainer.setVisibility(View.VISIBLE); - } else { - receivedContainer.setVisibility(View.GONE); - } - } - } - - private void updateExpirationTime(final MessageRecord messageRecord) { - if (messageRecord.getExpiresIn() <= 0 || messageRecord.getExpireStarted() <= 0) { - expiresContainer.setVisibility(View.GONE); - return; - } - - expiresContainer.setVisibility(View.VISIBLE); - Util.runOnMain(new Runnable() { - @Override - public void run() { - long elapsed = System.currentTimeMillis() - messageRecord.getExpireStarted(); - long remaining = messageRecord.getExpiresIn() - elapsed; - - String duration = ExpirationUtil.getExpirationDisplayValue(MessageDetailsActivity.this, Math.max((int)(remaining / 1000), 1)); - expiresInText.setText(duration); - - if (running) { - Util.runOnMainDelayed(this, 500); - } - } - }); - } - - private void updateRecipients(MessageRecord messageRecord, Recipient recipient, List recipients) { - final int toFromRes; - if (messageRecord.isMms() && !messageRecord.isPush() && !messageRecord.isOutgoing()) { - toFromRes = R.string.message_details_header__with; - } else if (messageRecord.isOutgoing()) { - toFromRes = R.string.message_details_header__to; - } else { - toFromRes = R.string.message_details_header__from; - } - toFrom.setText(toFromRes); - conversationItem.bind(messageRecord, Optional.absent(), Optional.absent(), glideRequests, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient, null, false); - Parcelable state = recipientsList.onSaveInstanceState(); - recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, glideRequests, messageRecord, recipients, isPushGroup)); - recipientsList.onRestoreInstanceState(state); - } - - private void inflateMessageViewIfAbsent(MessageRecord messageRecord) { - if (conversationItem == null) { - if (messageRecord.isGroupAction()) { - conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_update, itemParent, false); - } else if (messageRecord.isOutgoing()) { - conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_sent_multimedia, itemParent, false); - } else { - conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_received_multimedia, itemParent, false); - } - itemParent.addView(conversationItem); - } - } - - private @Nullable MessageRecord getMessageRecord(Context context, Cursor cursor, String type) { - switch (type) { - case MmsSmsDatabase.SMS_TRANSPORT: - SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - SmsDatabase.Reader reader = smsDatabase.readerFor(cursor); - return reader.getNext(); - case MmsSmsDatabase.MMS_TRANSPORT: - MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context); - MmsDatabase.Reader mmsReader = mmsDatabase.readerFor(cursor); - return mmsReader.getNext(); - default: - throw new AssertionError("no valid message type specified"); - } - } - - private void copyToClipboard(@NonNull String text) { - ((ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("text", text)); - } - - @Override - public @NonNull Loader onCreateLoader(int id, Bundle args) { - return new MessageDetailsLoader(this, getIntent().getStringExtra(TYPE_EXTRA), - getIntent().getLongExtra(MESSAGE_ID_EXTRA, -1)); - } - - @Override - public void onLoadFinished(@NonNull Loader loader, Cursor cursor) { - MessageRecord messageRecord = getMessageRecord(this, cursor, getIntent().getStringExtra(TYPE_EXTRA)); - - if (messageRecord == null) { - finish(); - } else { - new MessageRecipientAsyncTask(this, messageRecord).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - - @Override - public void onLoaderReset(@NonNull Loader loader) { - recipientsList.setAdapter(null); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - super.onOptionsItemSelected(item); - - switch (item.getItemId()) { - case android.R.id.home: finish(); return true; - } - - return false; - } - - @SuppressLint("StaticFieldLeak") - private class MessageRecipientAsyncTask extends AsyncTask> { - - private final WeakReference weakContext; - private final MessageRecord messageRecord; - - MessageRecipientAsyncTask(@NonNull Context context, @NonNull MessageRecord messageRecord) { - this.weakContext = new WeakReference<>(context); - this.messageRecord = messageRecord; - } - - protected Context getContext() { - return weakContext.get(); - } - - @Override - public List doInBackground(Void... voids) { - Context context = getContext(); - - if (context == null) { - Log.w(TAG, "associated context is destroyed, finishing early"); - return null; - } - - List recipients = new LinkedList<>(); - - if (!messageRecord.getRecipient().isGroup()) { - recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), messageRecord.isUnidentified(), -1)); - } else { - List receiptInfoList = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageRecord.getId()); - - if (receiptInfoList.isEmpty()) { - List group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); - - for (Recipient recipient : group) { - recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, -1)); - } - } else { - for (GroupReceiptInfo info : receiptInfoList) { - recipients.add(new RecipientDeliveryStatus(Recipient.resolved(info.getRecipientId()), - getStatusFor(info.getStatus(), messageRecord.isPending(), messageRecord.isFailed()), - info.isUnidentified(), - info.getTimestamp())); - } - } - } - - return recipients; - } - - @Override - public void onPostExecute(List recipients) { - if (getContext() == null) { - Log.w(TAG, "AsyncTask finished with a destroyed context, leaving early."); - return; - } - - inflateMessageViewIfAbsent(messageRecord); - updateRecipients(messageRecord, messageRecord.getRecipient(), recipients); - - boolean isGroupNetworkFailure = messageRecord.isFailed() && !messageRecord.getNetworkFailures().isEmpty(); - boolean isIndividualNetworkFailure = messageRecord.isFailed() && !isPushGroup && messageRecord.getIdentityKeyMismatches().isEmpty(); - - if (isGroupNetworkFailure || isIndividualNetworkFailure) { - errorText.setVisibility(View.VISIBLE); - resendButton.setVisibility(View.VISIBLE); - resendButton.setOnClickListener(this::onResendClicked); - metadataContainer.setVisibility(View.GONE); - } else if (messageRecord.isFailed()) { - errorText.setVisibility(View.VISIBLE); - resendButton.setVisibility(View.GONE); - resendButton.setOnClickListener(null); - metadataContainer.setVisibility(View.GONE); - } else { - updateTransport(messageRecord); - updateTime(messageRecord); - updateExpirationTime(messageRecord); - errorText.setVisibility(View.GONE); - resendButton.setVisibility(View.GONE); - resendButton.setOnClickListener(null); - metadataContainer.setVisibility(View.VISIBLE); - } - } - - private RecipientDeliveryStatus.Status getStatusFor(int deliveryReceiptCount, int readReceiptCount, boolean pending) { - if (readReceiptCount > 0) return RecipientDeliveryStatus.Status.READ; - else if (deliveryReceiptCount > 0) return RecipientDeliveryStatus.Status.DELIVERED; - else if (!pending) return RecipientDeliveryStatus.Status.SENT; - else return RecipientDeliveryStatus.Status.PENDING; - } - - private RecipientDeliveryStatus.Status getStatusFor(int groupStatus, boolean pending, boolean failed) { - if (groupStatus == GroupReceiptDatabase.STATUS_READ) return RecipientDeliveryStatus.Status.READ; - else if (groupStatus == GroupReceiptDatabase.STATUS_DELIVERED) return RecipientDeliveryStatus.Status.DELIVERED; - else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && failed) return RecipientDeliveryStatus.Status.UNKNOWN; - else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && !pending) return RecipientDeliveryStatus.Status.SENT; - else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED) return RecipientDeliveryStatus.Status.PENDING; - else if (groupStatus == GroupReceiptDatabase.STATUS_UNKNOWN) return RecipientDeliveryStatus.Status.UNKNOWN; - throw new AssertionError(); - } - - private void onResendClicked(View v) { - resendButton.setVisibility(View.GONE); - SignalExecutors.BOUNDED.execute(() -> MessageSender.resend(MessageDetailsActivity.this, messageRecord)); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java deleted file mode 100644 index 12a290cc8..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.content.Context; -import androidx.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.BaseAdapter; - -import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.mms.GlideRequests; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientId; -import org.thoughtcrime.securesms.util.Conversions; -import org.thoughtcrime.securesms.util.adapter.StableIdGenerator; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.List; - -class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.RecyclerListener { - - private final Context context; - private final GlideRequests glideRequests; - private final MessageRecord record; - private final List members; - private final boolean isPushGroup; - private final StableIdGenerator idGenerator; - - MessageDetailsRecipientAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, - @NonNull MessageRecord record, @NonNull List members, - boolean isPushGroup) - { - this.context = context; - this.glideRequests = glideRequests; - this.record = record; - this.isPushGroup = isPushGroup; - this.members = members; - this.idGenerator = new StableIdGenerator<>(); - } - - @Override - public int getCount() { - return members.size(); - } - - @Override - public Object getItem(int position) { - return members.get(position); - } - - @Override - public long getItemId(int position) { - return idGenerator.getId(members.get(position).recipient.getId()); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(context).inflate(R.layout.message_recipient_list_item, parent, false); - } - - RecipientDeliveryStatus member = members.get(position); - - ((MessageRecipientListItem)convertView).set(glideRequests, record, member, isPushGroup); - return convertView; - } - - @Override - public void onMovedToScrapHeap(View view) { - ((MessageRecipientListItem)view).unbind(); - } - - - static class RecipientDeliveryStatus { - - enum Status { - UNKNOWN, PENDING, SENT, DELIVERED, READ - } - - private final Recipient recipient; - private final Status deliveryStatus; - private final boolean isUnidentified; - private final long timestamp; - - RecipientDeliveryStatus(Recipient recipient, Status deliveryStatus, boolean isUnidentified, long timestamp) { - this.recipient = recipient; - this.deliveryStatus = deliveryStatus; - this.isUnidentified = isUnidentified; - this.timestamp = timestamp; - } - - Status getDeliveryStatus() { - return deliveryStatus; - } - - boolean isUnidentified() { - return isUnidentified; - } - - public long getTimestamp() { - return timestamp; - } - - public Recipient getRecipient() { - return recipient; - } - - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/MessageRecipientListItem.java b/app/src/main/java/org/thoughtcrime/securesms/MessageRecipientListItem.java deleted file mode 100644 index 3ff3016c9..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/MessageRecipientListItem.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2014 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus; -import org.thoughtcrime.securesms.components.AvatarImageView; -import org.thoughtcrime.securesms.components.DeliveryStatusView; -import org.thoughtcrime.securesms.components.FromTextView; -import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; -import org.thoughtcrime.securesms.database.documents.NetworkFailure; -import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.mms.GlideRequests; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientForeverObserver; -import org.thoughtcrime.securesms.util.TextSecurePreferences; - -/** - * A simple view to show the recipients of a message - * - * @author Jake McGinty - */ -public class MessageRecipientListItem extends RelativeLayout - implements RecipientForeverObserver -{ - @SuppressWarnings("unused") - private final static String TAG = MessageRecipientListItem.class.getSimpleName(); - - private RecipientDeliveryStatus member; - private GlideRequests glideRequests; - private FromTextView fromView; - private TextView errorDescription; - private TextView actionDescription; - private Button conflictButton; - private AvatarImageView contactPhotoImage; - private ImageView unidentifiedDeliveryIcon; - private DeliveryStatusView deliveryStatusView; - - public MessageRecipientListItem(Context context) { - super(context); - } - - public MessageRecipientListItem(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - this.fromView = findViewById(R.id.from); - this.errorDescription = findViewById(R.id.error_description); - this.actionDescription = findViewById(R.id.action_description); - this.contactPhotoImage = findViewById(R.id.contact_photo_image); - this.conflictButton = findViewById(R.id.conflict_button); - this.unidentifiedDeliveryIcon = findViewById(R.id.ud_indicator); - this.deliveryStatusView = findViewById(R.id.delivery_status); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - observeMember(); - } - - @Override - protected void onDetachedFromWindow() { - unsubscribeFromMember(); - super.onDetachedFromWindow(); - } - - public void set(final GlideRequests glideRequests, - final MessageRecord record, - final RecipientDeliveryStatus member, - final boolean isPushGroup) - { - unsubscribeFromMember(); - - this.glideRequests = glideRequests; - this.member = member; - observeMember(); - - fromView.setText(member.getRecipient()); - contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false); - setIssueIndicators(record, isPushGroup); - unidentifiedDeliveryIcon.setVisibility(TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()) && member.isUnidentified() ? VISIBLE : GONE); - } - - private void observeMember() { - if (isAttachedToWindow() && member != null && member.getRecipient() != null) { - member.getRecipient().live().observeForever(this); - } - } - - private void unsubscribeFromMember() { - if (member != null && member.getRecipient() != null) member.getRecipient().live().removeForeverObserver(this); - } - - private void setIssueIndicators(final MessageRecord record, - final boolean isPushGroup) - { - final NetworkFailure networkFailure = getNetworkFailure(record); - final IdentityKeyMismatch keyMismatch = networkFailure == null ? getKeyMismatch(record) : null; - - String errorText = ""; - - if (keyMismatch != null) { - conflictButton.setVisibility(View.VISIBLE); - - errorText = getContext().getString(R.string.MessageDetailsRecipient_new_safety_number); - conflictButton.setOnClickListener(v -> new ConfirmIdentityDialog(getContext(), record, keyMismatch).show()); - } else if ((networkFailure != null && !record.isPending()) || (!isPushGroup && record.isFailed())) { - conflictButton.setVisibility(View.GONE); - errorText = getContext().getString(R.string.MessageDetailsRecipient_failed_to_send); - } else { - if (record.isOutgoing()) { - if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.PENDING || member.getDeliveryStatus() == RecipientDeliveryStatus.Status.UNKNOWN) { - deliveryStatusView.setVisibility(View.GONE); - } else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.READ) { - deliveryStatusView.setRead(); - deliveryStatusView.setVisibility(View.VISIBLE); - } else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.DELIVERED) { - deliveryStatusView.setDelivered(); - deliveryStatusView.setVisibility(View.VISIBLE); - } else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.SENT) { - deliveryStatusView.setSent(); - deliveryStatusView.setVisibility(View.VISIBLE); - } - } else { - deliveryStatusView.setVisibility(View.GONE); - } - - conflictButton.setVisibility(View.GONE); - } - - errorDescription.setText(errorText); - errorDescription.setVisibility(TextUtils.isEmpty(errorText) ? View.GONE : View.VISIBLE); - } - - private NetworkFailure getNetworkFailure(final MessageRecord record) { - if (record.hasNetworkFailures()) { - for (final NetworkFailure failure : record.getNetworkFailures()) { - if (failure.getRecipientId(getContext()).equals(member.getRecipient().getId())) { - return failure; - } - } - } - return null; - } - - private IdentityKeyMismatch getKeyMismatch(final MessageRecord record) { - if (record.isIdentityMismatchFailure()) { - for (final IdentityKeyMismatch mismatch : record.getIdentityKeyMismatches()) { - if (mismatch.getRecipientId(getContext()).equals(member.getRecipient().getId())) { - return mismatch; - } - } - } - return null; - } - - public void unbind() { - unsubscribeFromMember(); - } - - @Override - public void onRecipientChanged(@NonNull Recipient recipient) { - if (this.member != null && this.member.getRecipient().equals(recipient)) { - Log.d(TAG, "onRecipientChanged -- valid"); - fromView.setText(recipient); - contactPhotoImage.setAvatar(glideRequests, recipient, false); - } else { - Log.d(TAG, "onRecipientChanged -- invalid"); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 3539433ec..11060918f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -60,7 +60,6 @@ import com.annimon.stream.Stream; import com.google.android.collect.Sets; import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.MessageDetailsActivity; import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.Attachment; @@ -74,7 +73,6 @@ import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickList import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase; -import org.thoughtcrime.securesms.database.MmsSmsDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord; @@ -87,6 +85,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.longmessage.LongMessageActivity; import org.thoughtcrime.securesms.mediasend.Media; +import org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity; import org.thoughtcrime.securesms.messagerequests.MessageRequestViewModel; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -690,13 +689,7 @@ public class ConversationFragment extends Fragment { private void handleDisplayDetails(MessageRecord message) { - Intent intent = new Intent(getActivity(), org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity.class); - intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, message.getId()); - intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, threadId); - intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT); - intent.putExtra(MessageDetailsActivity.RECIPIENT_EXTRA, recipient.getId()); - intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, recipient.get().isGroup() && message.isPush()); - startActivity(intent); + startActivity(MessageDetailsActivity.getIntentForMessageDetails(requireContext(), message, recipient.getId(), threadId)); } private void handleForwardMessage(MessageRecord message) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 2742a5439..9a9be3bd1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -58,7 +58,6 @@ import com.annimon.stream.Stream; import org.thoughtcrime.securesms.BindableConversationItem; import org.thoughtcrime.securesms.ConfirmIdentityDialog; import org.thoughtcrime.securesms.MediaPreviewActivity; -import org.thoughtcrime.securesms.MessageDetailsActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.components.AlertView; @@ -77,7 +76,6 @@ import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsDatabase; -import org.thoughtcrime.securesms.database.MmsSmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord; @@ -92,6 +90,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.ImageSlide; import org.thoughtcrime.securesms.mms.PartAuthority; @@ -109,7 +108,6 @@ import org.thoughtcrime.securesms.revealable.ViewOnceUtil; import org.thoughtcrime.securesms.stickers.StickerUrl; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.DynamicTheme; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.LongClickCopySpan; import org.thoughtcrime.securesms.util.LongClickMovementMethod; import org.thoughtcrime.securesms.util.SearchUtil; @@ -1377,13 +1375,7 @@ public class ConversationItem extends LinearLayout implements BindableConversati if (!shouldInterceptClicks(messageRecord) && parent != null) { parent.onClick(v); } else if (messageRecord.isFailed()) { - Intent intent = new Intent(context, org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity.class); - intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, messageRecord.getId()); - intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, messageRecord.getThreadId()); - intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT); - intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, groupThread && messageRecord.isPush()); - intent.putExtra(MessageDetailsActivity.RECIPIENT_EXTRA, conversationRecipient.getId()); - context.startActivity(intent); + context.startActivity(MessageDetailsActivity.getIntentForMessageDetails(context, messageRecord, conversationRecipient.getId(), messageRecord.getThreadId())); } else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) { handleApproveIdentity(); } else if (messageRecord.isPendingInsecureSmsFallback()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsActivity.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsActivity.java index 2b8711f3e..4253afde9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsActivity.java @@ -1,16 +1,21 @@ package org.thoughtcrime.securesms.messagedetails; +import android.content.Context; +import android.content.Intent; import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; import android.view.MenuItem; +import androidx.annotation.NonNull; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.RecyclerView; import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.color.MaterialColor; +import org.thoughtcrime.securesms.database.MmsSmsDatabase; +import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.messagedetails.MessageDetailsAdapter.MessageDetailsViewState; import org.thoughtcrime.securesms.messagedetails.MessageDetailsViewModel.Factory; import org.thoughtcrime.securesms.mms.GlideApp; @@ -25,10 +30,10 @@ import java.util.List; public final class MessageDetailsActivity extends PassphraseRequiredActionBarActivity { - public static final String MESSAGE_ID_EXTRA = "message_id"; - public static final String THREAD_ID_EXTRA = "thread_id"; - public static final String TYPE_EXTRA = "type"; - public static final String RECIPIENT_EXTRA = "recipient_id"; + private static final String MESSAGE_ID_EXTRA = "message_id"; + private static final String THREAD_ID_EXTRA = "thread_id"; + private static final String TYPE_EXTRA = "type"; + private static final String RECIPIENT_EXTRA = "recipient_id"; private GlideRequests glideRequests; private MessageDetailsViewModel viewModel; @@ -36,6 +41,15 @@ public final class MessageDetailsActivity extends PassphraseRequiredActionBarAct private DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme(); + public static @NonNull Intent getIntentForMessageDetails(@NonNull Context context, @NonNull MessageRecord message, @NonNull RecipientId recipientId, long threadId) { + Intent intent = new Intent(context, MessageDetailsActivity.class); + intent.putExtra(MESSAGE_ID_EXTRA, message.getId()); + intent.putExtra(THREAD_ID_EXTRA, threadId); + intent.putExtra(TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT); + intent.putExtra(RECIPIENT_EXTRA, recipientId); + return intent; + } + @Override protected void onPreCreate() { dynamicTheme.onCreate(this); @@ -44,7 +58,7 @@ public final class MessageDetailsActivity extends PassphraseRequiredActionBarAct @Override protected void onCreate(Bundle savedInstanceState, boolean ready) { super.onCreate(savedInstanceState, ready); - setContentView(R.layout.message_details_2_activity); + setContentView(R.layout.message_details_activity); glideRequests = GlideApp.with(this); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsAdapter.java index 4662fce85..1e4030ae6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsAdapter.java @@ -32,11 +32,11 @@ final class MessageDetailsAdapter extends ListAdapter new ConfirmIdentityDialog(itemView.getContext(), data.getMessageRecord(), data.getKeyMismatchFailure()).show()); } else if ((data.getNetworkFailure() != null && !data.getMessageRecord().isPending()) || (!data.getMessageRecord().getRecipient().isPushGroup() && data.getMessageRecord().isFailed())) { timestamp.setVisibility(View.GONE); error.setVisibility(View.VISIBLE); conflictButton.setVisibility(View.GONE); - error.setText(itemView.getContext().getString(R.string.MessageDetailsRecipient_failed_to_send)); + error.setText(itemView.getContext().getString(R.string.message_details_recipient__failed_to_send)); } else { timestamp.setVisibility(View.VISIBLE); error.setVisibility(View.GONE); diff --git a/app/src/main/res/layout/message_details_2_activity.xml b/app/src/main/res/layout/message_details_2_activity.xml deleted file mode 100644 index 05004eb82..000000000 --- a/app/src/main/res/layout/message_details_2_activity.xml +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/message_details_2_header.xml b/app/src/main/res/layout/message_details_2_header.xml deleted file mode 100644 index 1e8fae2b1..000000000 --- a/app/src/main/res/layout/message_details_2_header.xml +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - - - - - - - - - - - -